[Python-checkins] benchmarks: Add the chameleon benchmark from PyPy.
brett.cannon
python-checkins at python.org
Tue Sep 25 17:00:25 CEST 2012
http://hg.python.org/benchmarks/rev/e2dd5d15cd78
changeset: 182:e2dd5d15cd78
user: Brett Cannon <brett at python.org>
date: Tue Sep 25 11:00:17 2012 -0400
summary:
Add the chameleon benchmark from PyPy.
files:
lib/Chameleon-2.9.2/.gitignore | 12 +
lib/Chameleon-2.9.2/CHANGES.rst | 1075 ++++++
lib/Chameleon-2.9.2/COPYRIGHT.txt | 7 +
lib/Chameleon-2.9.2/LICENSE.txt | 185 +
lib/Chameleon-2.9.2/Makefile | 89 +
lib/Chameleon-2.9.2/PKG-INFO | 1122 ++++++
lib/Chameleon-2.9.2/README.rst | 25 +
lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py | 128 +
lib/Chameleon-2.9.2/benchmarks/bm_mako.py | 153 +
lib/Chameleon-2.9.2/benchmarks/util.py | 51 +
lib/Chameleon-2.9.2/distribute_setup.py | 485 ++
lib/Chameleon-2.9.2/docs/conf.py | 194 +
lib/Chameleon-2.9.2/docs/configuration.rst | 43 +
lib/Chameleon-2.9.2/docs/index.rst | 217 +
lib/Chameleon-2.9.2/docs/integration.rst | 41 +
lib/Chameleon-2.9.2/docs/library.rst | 238 +
lib/Chameleon-2.9.2/docs/reference.rst | 1695 ++++++++++
lib/Chameleon-2.9.2/setup.cfg | 14 +
lib/Chameleon-2.9.2/setup.py | 90 +
lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO | 1122 ++++++
lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt | 380 ++
lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt | 1 +
lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe | 1 +
lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt | 1 +
lib/Chameleon-2.9.2/src/chameleon/__init__.py | 5 +
lib/Chameleon-2.9.2/src/chameleon/ast24.py | 135 +
lib/Chameleon-2.9.2/src/chameleon/astutil.py | 926 +++++
lib/Chameleon-2.9.2/src/chameleon/benchmark.py | 478 ++
lib/Chameleon-2.9.2/src/chameleon/codegen.py | 221 +
lib/Chameleon-2.9.2/src/chameleon/compiler.py | 1553 +++++++++
lib/Chameleon-2.9.2/src/chameleon/config.py | 47 +
lib/Chameleon-2.9.2/src/chameleon/exc.py | 289 +
lib/Chameleon-2.9.2/src/chameleon/i18n.py | 120 +
lib/Chameleon-2.9.2/src/chameleon/interfaces.py | 102 +
lib/Chameleon-2.9.2/src/chameleon/loader.py | 174 +
lib/Chameleon-2.9.2/src/chameleon/metal.py | 23 +
lib/Chameleon-2.9.2/src/chameleon/namespaces.py | 9 +
lib/Chameleon-2.9.2/src/chameleon/nodes.py | 210 +
lib/Chameleon-2.9.2/src/chameleon/parser.py | 238 +
lib/Chameleon-2.9.2/src/chameleon/program.py | 38 +
lib/Chameleon-2.9.2/src/chameleon/py25.py | 36 +
lib/Chameleon-2.9.2/src/chameleon/py26.py | 15 +
lib/Chameleon-2.9.2/src/chameleon/tal.py | 479 ++
lib/Chameleon-2.9.2/src/chameleon/tales.py | 541 +++
lib/Chameleon-2.9.2/src/chameleon/template.py | 332 +
lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt | 18 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt | 21 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt | 14 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt | 20 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt | 2 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt | 20 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt | 22 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt | 19 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049.xml | Bin
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050.xml | Bin
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051.xml | Bin
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt | 27 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt | 23 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt | 2 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt | 28 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt | 2 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt | 18 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt | 14 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt | 22 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt | 14 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt | 23 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt | 10 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/039.pt | 0
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt | 12 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt | 4 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt | 7 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt | 27 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt | 13 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt | 6 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt | 19 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt | 19 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt | 17 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt | 11 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt | 16 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt | 3 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt | 15 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt | 9 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt | 18 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt | 25 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html | 8 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt | 5 +
lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt | 1 +
lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py | 40 +
lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py | 79 +
lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py | 92 +
lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py | 124 +
lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py | 679 ++++
lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py | 47 +
lib/Chameleon-2.9.2/src/chameleon/tokenize.py | 144 +
lib/Chameleon-2.9.2/src/chameleon/utils.py | 429 ++
lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py | 1 +
lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py | 30 +
lib/Chameleon-2.9.2/src/chameleon/zpt/program.py | 751 ++++
lib/Chameleon-2.9.2/src/chameleon/zpt/template.py | 409 ++
lib/Chameleon-2.9.2/src/ordereddict.py | 127 +
lib/Chameleon-2.9.2/tox.ini | 53 +
make_perf3.sh | 9 +-
perf.py | 16 +-
performance/bm_chameleon.py | 40 +
385 files changed, 18931 insertions(+), 3 deletions(-)
diff --git a/lib/Chameleon-2.9.2/.gitignore b/lib/Chameleon-2.9.2/.gitignore
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/.gitignore
@@ -0,0 +1,12 @@
+*.pyc
+*.egg
+*.egg-info
+.coverage
+.tox/
+coverage.xml
+nosetests.xml
+*.tar.gz
+env25/
+env26/
+env27/
+env32/
diff --git a/lib/Chameleon-2.9.2/CHANGES.rst b/lib/Chameleon-2.9.2/CHANGES.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/CHANGES.rst
@@ -0,0 +1,1075 @@
+Changes
+=======
+
+2.9.2 (2012-06-06)
+------------------
+
+Bugfixes:
+
+- Fixed a PyPy incompatibility.
+
+- Fixed issue #109 which caused testing failures on some platforms.
+
+2.9.1 (2012-06-01)
+------------------
+
+Bugfixes:
+
+- Fixed issue #103. The ``tal:on-error`` statement now always adds an
+ explicit end-tag to the element, even with a substitution content of
+ nothing.
+
+- Fixed issue #113. The ``tal:on-error`` statement now works correctly
+ also for dynamic attributes. That is, the fallback tag now includes
+ only static attributes.
+
+- Fixed name error which prevented the benchmark from running
+ correctly.
+
+Compatibility:
+
+- Fixed deprecation warning on Python 3 for zope interface implements
+ declaration. This fixes issue #116.
+
+2.9.0 (2012-05-31)
+------------------
+
+Features:
+
+- The translation function now gets the ``econtext`` argument as the
+ value for ``context``. Note that historically, this was usually an
+ HTTP request which might provide language negotiation data through a
+ dictionary interface.
+ [alvinyue]
+
+Bugfixes:
+
+- Fixed import alias issue which would lead to a syntax error in
+ generated Python code. Fixes issue #114.
+
+2.8.5 (2012-05-02)
+------------------
+
+Bugfixes:
+
+- Fixed minor installation issues on Python 2.5 and 3.
+ [ppaez]
+
+- Ensure output is unicode even when trivial (an empty string).
+
+2.8.4 (2012-04-18)
+------------------
+
+Features:
+
+- In exception output, long filenames are now truncated to 60
+ characters of output, preventing line wrap which makes it difficult
+ to scan the exception output.
+
+Bugfixes:
+
+- Include filename and location in exception output for exceptions
+ raised during compilation.
+
+- If a trivial translation substitution variable is given (i.e. an
+ empty string), simply ignore it. This fixes issue #106.
+
+2.8.3 (2012-04-16)
+------------------
+
+Features:
+
+- Log template source on debug-level before cooking.
+
+- The `target_language` argument, if given, is now available as a
+ variable in templates.
+
+2.8.2 (2012-03-30)
+------------------
+
+Features:
+
+- Temporary caches used in debug mode are cleaned up eagerly, rather
+ than waiting for process termination.
+ [mitchellrj]
+
+Bugfixes:
+
+- The `index`, `start` and `end` methods on the TAL repeat object are
+ now callable. This fixes an incompatibility with ZPT.
+
+- The loader now correctly handles absolute paths on Windows.
+ [rdale]
+
+2.8.1 (2012-03-29)
+------------------
+
+Features:
+
+- The exception formatter now lists errors in 'wrapping order'. This
+ means that the innermost, and presumably most relevant exception is
+ shown last.
+
+Bugfixes:
+
+- The exception formatter now correctly recognizes nested errors and
+ does not rewrap the dynamically generated exception class.
+
+- The exception formatter now correctly sets the ``__module__``
+ attribute to that of the original exception class.
+
+2.8.0 (2012-02-29)
+------------------
+
+Features:
+
+- Added support for code blocks using the `<?python ... ?>` processing
+ instruction syntax.
+
+ The scope is name assignments is up until the nearest macro
+ definition, or the template itself if macros are not used.
+
+Bugfixes:
+
+- Fall back to the exception class' ``__new__`` method to safely
+ create an exception object that is not implemented in Python.
+
+- The exception formatter now keeps track of already formatted
+ exceptions, and ignores them from further output.
+
+2.7.4 (2012-02-27)
+------------------
+
+- The error handler now invokes the ``__init__`` method of
+ ``BaseException`` instead of the possibly overriden method (which
+ may take required arguments). This fixes issue #97.
+ [j23d, malthe]
+
+2.7.3 (2012-01-16)
+------------------
+
+Bugfixes:
+
+- The trim whitespace option now correctly trims actual whitespace to
+ a single character, appearing either to the left or to the right of
+ an element prefix or suffix string.
+
+2.7.2 (2012-01-08)
+------------------
+
+Features:
+
+- Added option ``trim_attribute_space`` that decides whether attribute
+ whitespace is stripped (at most down to a single space). This option
+ exists to provide compatibility with the reference
+ implementation. Fixes issue #85.
+
+Bugfixes:
+
+- Ignore unhashable builtins when generating a reverse builtin
+ map to quickly look up a builtin value.
+ [malthe]
+
+- Apply translation mapping even when a translation function is not
+ available. This fixes issue #83.
+ [malthe]
+
+- Fixed issue #80. The translation domain for a slot is defined by the
+ source document, i.e. the template providing the content for a slot
+ whether it be the default or provided through ``metal:fill-slot``.
+ [jcbrand]
+
+- In certain circumstances, a Unicode non-breaking space character would cause
+ a define clause to fail to parse.
+
+2.7.1 (2011-12-29)
+------------------
+
+Features:
+
+- Enable expression interpolation in CDATA.
+
+- The page template class now implements dictionary access to macros::
+
+ template[name]
+
+ This is a short-hand for::
+
+ template.macros[name]
+
+Bugfixes:
+
+- An invalid define clause would be silently ignored; we now raise a
+ language error exception. This fixes issue #79.
+
+- Fixed regression where ``${...}`` interpolation expressions could
+ not span multiple lines. This fixes issue #77.
+
+2.7.0 (2011-12-13)
+------------------
+
+Features:
+
+- The ``load:`` expression now derives from the string expression such
+ that the ``${...}`` operator can be used for expression
+ interpolation.
+
+- The ``load:`` expression now accepts asset specs; these are resolved
+ by the ``pkg_resources.resource_filename`` function::
+
+ <package_name>:<path>
+
+ An example from the test suite::
+
+ chameleon:tests/inputs/hello_world.pt
+
+Bugfixes:
+
+- If an attribute name for translation was not a valid Python
+ identifier, the compiler would generate invalid code. This has been
+ fixed, and the compiler now also throws an exception if an attribute
+ specification contains a comma. (Note that the only valid separator
+ character is the semicolon, when specifying attributes for
+ translation via the ``i18n:translate`` statement). This addresses
+ issue #76.
+
+2.6.2 (2011-12-08)
+------------------
+
+Bugfixes:
+
+- Fixed issue where ``tal:on-error`` would not respect
+ ``tal:omit-tag`` or namespace elements which are omitted by default
+ (such as ``<tal:block />``).
+
+- Fixed issue where ``macros`` attribute would not be available on
+ file-based templates due to incorrect initialization.
+
+- The ``TryExcept`` and ``TryFinally`` AST nodes are not available on
+ Python 3.3. These have been aliased to ``Try``. This fixes issue
+ #75.
+
+Features:
+
+- The TAL repeat item now makes a security declaration that grants
+ access to unprotected subobjects on the Zope 2 platform::
+
+ __allow_access_to_unprotected_subobjects__ = True
+
+ This is required for legacy compatibility and does not affect other
+ environments.
+
+- The template object now has a method ``write(body)`` which
+ explicitly decodes and cooks a string input.
+
+- Added configuration option ``loader_class`` which sets the class
+ used to create the template loader object.
+
+ The class (essentially a callable) is created at template
+ construction time.
+
+2.6.1 (2011-11-30)
+------------------
+
+Bugfixes:
+
+- Decode HTML entities in expression interpolation strings. This fixes
+ issue #74.
+
+- Allow ``xml`` and ``xmlns`` attributes on TAL, I18N and METAL
+ namespace elements. This fixes issue #73.
+
+2.6.0 (2011-11-24)
+------------------
+
+Features:
+
+- Added support for implicit translation:
+
+ The ``implicit_i18n_translate`` option enables implicit translation
+ of text. The ``implicit_i18n_attributes`` enables implicit
+ translation of attributes. The latter must be a set and for an
+ attribute to be implicitly translated, its lowercase string value
+ must be included in the set.
+
+- Added option ``strict`` (enabled by default) which decides whether
+ expressions are required to be valid at compile time. That is, if
+ not set, an exception is only raised for an invalid expression at
+ evaluation time.
+
+- An expression error now results in an exception only if the
+ expression is attempted evaluated during a rendering.
+
+- Added a configuration option ``prepend_relative_search_path`` which
+ decides whether the path relative to a file-based template is
+ prepended to the load search path. The default is ``True``.
+
+- Added a configuration option ``search_path`` to the file-based
+ template class, which adds additional paths to the template load
+ instance bound to the ``load:`` expression. The option takes a
+ string path or an iterable yielding string paths. The default value
+ is the empty set.
+
+Bugfixes:
+
+- Exception instances now support pickle/unpickle.
+
+- An attributes in i18n:attributes no longer needs to match an
+ existing or dynamic attribute in order to appear in the
+ element. This fixes issue #66.
+
+2.5.3 (2011-10-23)
+------------------
+
+Bugfixes:
+
+- Fixed an issue where a nested macro slot definition would fail even
+ though there existed a parent macro definition. This fixes issue
+ #69.
+
+2.5.2 (2011-10-12)
+------------------
+
+Bugfixes:
+
+- Fixed an issue where technically invalid input would result in a
+ compiler error.
+
+Features:
+
+- The markup class now inherits from the unicode string type such that
+ it's compatible with the string interface.
+
+2.5.1 (2011-09-29)
+------------------
+
+Bugfixes:
+
+- The symbol names "convert", "decode" and "translate" are now no
+ longer set as read-only *compiler internals*. This fixes issue #65.
+
+- Fixed an issue where a macro extension chain nested two levels (a
+ template uses a macro that extends a macro) would lose the middle
+ slot definitions if slots were defined nested.
+
+ The compiler now throws an error if a nested slot definition is used
+ outside a macro extension context.
+
+2.5.0 (2011-09-23)
+------------------
+
+Features:
+
+- An expression type ``structure:`` is now available which wraps the
+ expression result as *structure* such that it is not escaped on
+ insertion, e.g.::
+
+ <div id="content">
+ ${structure: context.body}
+ </div>
+
+ This also means that the ``structure`` keyword for ``tal:content``
+ and ``tal:replace`` now has an alternative spelling via the
+ expression type ``structure:``.
+
+- The string-based template constructor now accepts encoded input.
+
+2.4.6 (2011-09-23)
+------------------
+
+Bugfixes:
+
+- The ``tal:on-error`` statement should catch all exceptions.
+
+- Fixed issue that would prevent escaping of interpolation expression
+ values appearing in text.
+
+2.4.5 (2011-09-21)
+------------------
+
+Bugfixes:
+
+- The ``tal:on-error`` handler should have a ``error`` variable
+ defined that has the value of the exception thrown.
+
+- The ``tal:on-error`` statement is a substitution statement and
+ should support the "text" and "structure" insertion methods.
+
+2.4.4 (2011-09-15)
+------------------
+
+Bugfixes:
+
+- An encoding specified in the XML document preamble is now read and
+ used to decode the template input to unicode. This fixes issue #55.
+
+- Encoded expression input on Python 3 is now correctly
+ decoded. Previously, the string representation output would be
+ included instead of an actually decoded string.
+
+- Expression result conversion steps are now correctly included in
+ error handling such that the exception output points to the
+ expression location.
+
+2.4.3 (2011-09-13)
+------------------
+
+Features:
+
+- When an encoding is provided, pass the 'ignore' flag to avoid
+ decoding issues with bad input.
+
+Bugfixes:
+
+- Fixed pypy compatibility issue (introduced in previous release).
+
+2.4.2 (2011-09-13)
+------------------
+
+Bugfixes:
+
+- Fixed an issue in the compiler where an internal variable (such as a
+ translation default value) would be cached, resulting in variable
+ scope corruption (see issue #49).
+
+2.4.1 (2011-09-08)
+------------------
+
+Bugfixes:
+
+- Fixed an issue where a default value for an attribute would
+ sometimes spill over into another attribute.
+
+- Fixed issue where the use of the ``default`` name in an attribute
+ interpolation expression would print the attribute value. This is
+ unexpected, because it's an expression, not a static text suitable
+ for output. An attribute value of ``default`` now correctly drops
+ the attribute.
+
+2.4.0 (2011-08-22)
+------------------
+
+Features:
+
+- Added an option ``boolean_attributes`` to evaluate and render a
+ provided set of attributes using a boolean logic: if the attribute
+ is a true value, the value will be the attribute name, otherwise the
+ attribute is dropped.
+
+ In the reference implementation, the following attributes are
+ configured as boolean values when the template is rendered in
+ HTML-mode::
+
+ "compact", "nowrap", "ismap", "declare", "noshade",
+ "checked", "disabled", "readonly", "multiple", "selected",
+ "noresize", "defer"
+
+ Note that in Chameleon, these attributes must be manually provided.
+
+Bugfixes:
+
+- The carriage return character (used on Windows platforms) would
+ incorrectly be included in Python comments.
+
+ It is now replaced with a line break.
+
+ This fixes issue #44.
+
+2.3.8 (2011-08-19)
+------------------
+
+- Fixed import error that affected Python 2.5 only.
+
+2.3.7 (2011-08-19)
+------------------
+
+Features:
+
+- Added an option ``literal_false`` that disables the default behavior
+ of dropping an attribute for a value of ``False`` (in addition to
+ ``None``). This modified behavior is the behavior exhibited in
+ reference implementation.
+
+Bugfixes:
+
+- Undo attribute special HTML attribute behavior (see previous
+ release).
+
+ This turned out not to be a compatible behavior; rather, boolean
+ values should simply be coerced to a string.
+
+ Meanwhile, the reference implementation does support an HTML mode in
+ which the special attribute behavior is exhibited.
+
+ We do not currently support this mode.
+
+2.3.6 (2011-08-18)
+------------------
+
+Features:
+
+- Certain HTML attribute names now have a special behavior for a
+ attribute value of ``True`` (or ``default`` if no default is
+ defined). For these attributes, this return value will result in the
+ name being printed as the value::
+
+ <input type="input" tal:attributes="checked True" />
+
+ will be rendered as::
+
+ <input type="input" checked="checked" />
+
+ This behavior is compatible with the reference implementation.
+
+2.3.5 (2011-08-18)
+------------------
+
+Features:
+
+- Added support for the set operator (``{item, item, ...}``).
+
+Bugfixes:
+
+- If macro is defined on the same element as a translation name, this
+ no longer results in a "translation name not allowed outside
+ translation" error. This fixes issue #43.
+
+- Attribute fallback to dictionary lookup now works on multiple items
+ (e.g. ``d1.d2.d2``). This fixes issue #42.
+
+2.3.4 (2011-08-16)
+------------------
+
+Features:
+
+- When inserting content in either attributes or text, a value of
+ ``True`` (like ``False`` and ``None``) will result in no
+ action.
+
+- Use statically assigned variables for ``"attrs"`` and
+ ``"default"``. This change yields a performance improvement of
+ 15-20%.
+
+- The template loader class now accepts an optional argument
+ ``default_extension`` which accepts a filename extension which will
+ be appended to the filename if there's not already an extension.
+
+Bugfixes:
+
+- The default symbol is now ``True`` for an attribute if the attribute
+ default is not provided. Note that the result is that the attribute
+ is dropped. This fixes issue #41.
+
+- Fixed an issue where assignment to a variable ``"type"`` would
+ fail. This fixes issue #40.
+
+- Fixed an issue where an (unsuccesful) assignment for a repeat loop
+ to a compiler internal name would not result in an error.
+
+- If the translation function returns the identical object, manually
+ coerce it to string. This fixes a compatibility issue with
+ translation functions which do not convert non-string objects to a
+ string value, but simply return them unchanged.
+
+2.3.3 (2011-08-15)
+------------------
+
+Features:
+
+- The ``load:`` expression now passes the initial keyword arguments to
+ its template loader (e.g. ``auto_reload`` and ``encoding``).
+
+- In the exception output, string variable values are now limited to a
+ limited output of characters, single line only.
+
+Bugfixes:
+
+- Fixed horizontal alignment of exception location info
+ (i.e. 'String:', 'Filename:' and 'Location:') such that they match
+ the template exception formatter.
+
+2.3.2 (2011-08-11)
+------------------
+
+Bugfixes:
+
+- Fixed issue where i18n:domain would not be inherited through macros
+ and slots. This fixes issue #37.
+
+2.3.1 (2011-08-11)
+------------------
+
+Features:
+
+- The ``Builtin`` node type may now be used to represent any Python
+ local or global name. This allows expression compilers to refer to
+ e.g. ``get`` or ``getitem``, or to explicit require a builtin object
+ such as one from the ``extra_builtins`` dictionary.
+
+Bugfixes:
+
+- Builtins which are not explicitly disallowed may now be redefined
+ and used as variables (e.g. ``nothing``).
+
+- Fixed compiler issue with circular node annotation loop.
+
+2.3 (2011-08-10)
+----------------
+
+Features:
+
+- Added support for the following syntax to disable inline evaluation
+ in a comment:
+
+ <!--? comment appears verbatim (no ${...} evaluation) -->
+
+ Note that the initial question mark character (?) will be omitted
+ from output.
+
+- The parser now accepts '<' and '>' in attributes. Note that this is
+ invalid markup. Previously, the '<' would not be accepted as a valid
+ attribute value, but this would result in an 'unexpected end tag'
+ error elsewhere. This fixes issue #38.
+
+- The expression compiler now provides methods ``assign_text`` and
+ ``assign_value`` such that a template engine might configure this
+ value conversion to support e.g. encoded strings.
+
+ Note that currently, the only client for the ``assign_text`` method
+ is the string expression type.
+
+- Enable template loader for string-based template classes. Note that
+ the ``filename`` keyword argument may be provided on initialization
+ to identify the template source by filename. This fixes issue #36.
+
+- Added ``extra_builtins`` option to the page template class. These
+ builtins are added to the default builtins dictionary at cook time
+ and may be provided at initialization using the ``extra_builtins``
+ keyword argument.
+
+Bugfixes:
+
+- If a translation domain is set for a fill slot, use this setting
+ instead of the macro template domain.
+
+- The Python expression compiler now correctly decodes HTML entities
+ ``'gt'`` and ``'lt'``. This fixes issue #32.
+
+- The string expression compiler now correctly handles encoded text
+ (when support for encoded strings is enabled). This fixes issue #35.
+
+- Fixed an issue where setting the ``filename`` attribute on a
+ file-based template would not automatically cause an invalidation.
+
+- Exceptions raised by Chameleon can now be copied via
+ ``copy.copy``. This fixes issue #36.
+ [leorochael]
+
+- If copying the exception fails in the exception handler, simply
+ re-raise the original exception and log a warning.
+
+2.2 (2011-07-28)
+----------------
+
+Features:
+
+- Added new expression type ``load:`` that allows loading a
+ template. Both relative and absolute paths are supported. If the
+ path given is relative, then it will be resolved with respect to the
+ directory of the template.
+
+- Added support for dynamic evaluation of expressions.
+
+ Note that this is to support legacy applications. It is not
+ currently wired into the provided template classes.
+
+- Template classes now have a ``builtins`` attribute which may be used
+ to define built-in variables always available in the template
+ variable scope.
+
+Incompatibilities:
+
+- The file-based template class no longer accepts a parameter
+ ``loader``. This parameter would be used to load a template from a
+ relative path, using a ``find(filename)`` method. This was however,
+ undocumented, and probably not very useful since we have the
+ ``TemplateLoader`` mechanism already.
+
+- The compiled template module now contains an ``initialize`` function
+ which takes values that map to the template builtins. The return
+ value of this function is a dictionary that contains the render
+ functions.
+
+Bugfixes:
+
+- The file-based template class no longer verifies the existance of a
+ template file (using ``os.lstat``). This now happens implicitly if
+ eager parsing is enabled, or otherwise when first needed (e.g. at
+ render time).
+
+ This is classified as a bug fix because the previous behavior was
+ probably not what you'd expect, especially if an application
+ initializes a lot of templates without needing to render them
+ immediately.
+
+2.1.1 (2011-07-28)
+------------------
+
+Features:
+
+- Improved exception display. The expression string is now shown in
+ the context of the original source (if available) with a marker
+ string indicating the location of the expression in the template
+ source.
+
+Bugfixes:
+
+- The ``structure`` insertion mode now correctly decodes entities for
+ any expression type (including ``string:``). This fixes issue #30.
+
+- Don't show internal variables in the exception formatter variable
+ listing.
+
+2.1 (2011-07-25)
+----------------
+
+Features:
+
+- Expression interpolation (using the ``${...}`` operator and
+ previously also ``$identifier``) now requires braces everywhere
+ except inside the ``string:`` expression type.
+
+ This change is motivated by a number of legacy templates in which
+ the interpolation format without braces ``$identifier`` appears as
+ text.
+
+2.0.2 (2011-07-25)
+------------------
+
+Bugfixes:
+
+- Don't use dynamic variable scope for lambda-scoped variables (#27).
+
+- Avoid duplication of exception class and message in traceback.
+
+- Fixed issue where a ``metal:fill-slot`` would be ignored if a macro
+ was set to be used on the same element (#16).
+
+2.0.1 (2011-07-23)
+------------------
+
+Bugfixes:
+
+- Fixed issue where global variable definition from macro slots would
+ fail (they would instead be local). This also affects error
+ reporting from inside slots because this would be recorded
+ internally as a global.
+
+- Fixed issue with template cache digest (used for filenames); modules
+ are now invalidated whenever any changes are made to the
+ distribution set available (packages on ``sys.path``).
+
+- Fixed exception handler to better let exceptions propagate through
+ the renderer.
+
+- The disk-based module compiler now mangles template source filenames
+ such that the output Python module is valid and at root level (dots
+ and hyphens are replaced by an underscore). This fixes issue #17.
+
+- Fixed translations (i18n) on Python 2.5.
+
+2.0 (2011-07-14)
+----------------
+
+- Point release.
+
+2.0-rc14 (2011-07-13)
+---------------------
+
+Bugfixes:
+
+- The tab character (``\t``) is now parsed correctly when used inside
+ tags.
+
+Features:
+
+- The ``RepeatDict`` class now works as a proxy behind a seperate
+ dictionary instance.
+
+- Added template constructor option ``keep_body`` which is a flag
+ (also available as a class attribute) that controls whether to save
+ the template body input in the ``body`` attribute.
+
+ This is disabled by default, unless debug-mode is enabled.
+
+- The page template loader class now accepts an optional ``formats``
+ argument which can be used to select an alternative template class.
+
+2.0-rc13 (2011-07-07)
+---------------------
+
+Bugfixes:
+
+- The backslash character (followed by optional whitespace and a line
+ break) was not correctly interpreted as a continuation for Python
+ expressions.
+
+Features:
+
+- The Python expression implementation is now more flexible for
+ external subclassing via a new ``parse`` method.
+
+2.0-rc12 (2011-07-04)
+---------------------
+
+Bugfixes:
+
+- Initial keyword arguments passed to a template now no longer "leak"
+ into the template variable space after a macro call.
+
+- An unexpected end tag is now an unrecoverable error.
+
+Features:
+
+- Improve exception output.
+
+2.0-rc11 (2011-05-26)
+---------------------
+
+Bugfixes:
+
+- Fixed issue where variable names that begin with an underscore were
+ seemingly allowed, but their use resulted in a compiler error.
+
+Features:
+
+- Template variable names are now allowed to be prefixed with a single
+ underscore, but not two or more (reserved for internal use).
+
+ Examples of valid names::
+
+ item
+ ITEM
+ _item
+ camelCase
+ underscore_delimited
+ help
+
+- Added support for Genshi's comment "drop" syntax::
+
+ <!--! This comment will be dropped -->
+
+ Note the additional exclamation (!) character.
+
+ This fixes addresses issue #10.
+
+2.0-rc10 (2011-05-24)
+---------------------
+
+Bugfixes:
+
+- The ``tal:attributes`` statement now correctly operates
+ case-insensitive. The attribute name given in the statement will
+ replace an existing attribute with the same name, without respect to
+ case.
+
+Features:
+
+- Added ``meta:interpolation`` statement to control expression
+ interpolation setting.
+
+ Strings that disable the setting: ``"off"`` and ``"false"``.
+ Strings that enable the setting: ``"on"`` and ``"true"``.
+
+- Expression interpolation now works inside XML comments.
+
+2.0-rc9 (2011-05-05)
+--------------------
+
+Features:
+
+- Better debugging support for string decode and conversion. If a
+ naive join fails, each element in the output will now be attempted
+ coerced to unicode to try and trigger the failure near to the bad
+ string.
+
+2.0-rc8 (2011-04-11)
+--------------------
+
+Bugfixes:
+
+- If a macro defines two slots with the same name, a caller will now
+ fill both with a single usage.
+
+- If a valid of ``None`` is provided as the translation function
+ argument, we now fall back to the class default.
+
+2.0-rc7 (2011-03-29)
+--------------------
+
+Bugfixes:
+
+- Fixed issue with Python 2.5 compatibility AST. This affected at
+ least PyPy 1.4.
+
+Features:
+
+- The ``auto_reload`` setting now defaults to the class value; the
+ base template class gives a default value of
+ ``chameleon.config.AUTO_RELOAD``. This change allows a subclass to
+ provide a custom default value (such as an application-specific
+ debug mode setting).
+
+
+2.0-rc6 (2011-03-19)
+--------------------
+
+Features:
+
+- Added support for ``target_language`` keyword argument to render
+ method. If provided, the argument will be curried onto the
+ translation function.
+
+Bugfixes:
+
+- The HTML entities 'lt', 'gt' and 'quot' appearing inside content
+ subtition expressions are now translated into their native character
+ values. This fixes an issue where you could not dynamically create
+ elements using the ``structure`` (which is possible in ZPT). The
+ need to create such structure stems from the lack of an expression
+ interpolation operator in ZPT.
+
+- Fixed duplicate file pointer issue with test suite (affected Windows
+ platforms only). This fixes issue #9.
+ [oliora]
+
+- Use already open file using ``os.fdopen`` when trying to write out
+ the module source. This fixes LP #731803.
+
+
+2.0-rc5 (2011-03-07)
+--------------------
+
+Bugfixes:
+
+- Fixed a number of issues concerning the escaping of attribute
+ values:
+
+ 1) Static attribute values are now included as they appear in the
+ source.
+
+ This means that invalid attribute values such as ``"true &&
+ false"`` are now left alone. It's not the job of the template
+ engine to correct such markup, at least not in the default mode
+ of operation.
+
+ 2) The string expression compiler no longer unescapes
+ values. Instead, this is left to each expression
+ compiler. Currently only the Python expression compiler unescapes
+ its input.
+
+ 3) The dynamic escape code sequence now correctly only replaces
+ ampersands that are part of an HTML escape format.
+
+Imports:
+
+- The page template classes and the loader class can now be imported
+ directly from the ``chameleon`` module.
+
+Features:
+
+- If a custom template loader is not provided, relative paths are now
+ resolved using ``os.abspath`` (i.e. to the current working
+ directory).
+
+- Absolute paths are normalized using ``os.path.normpath`` and
+ ``os.path.expanduser``. This ensures that all paths are kept in
+ their "canonical" form.
+
+
+2.0-rc4 (2011-03-03)
+--------------------
+
+Bugfixes:
+
+- Fixed an issue where the output of an end-to-end string expression
+ would raise an exception if the expression evaluated to ``None`` (it
+ should simply output nothing).
+
+- The ``convert`` function (which is configurable on the template
+ class level) now defaults to the ``translate`` function (at
+ run-time).
+
+ This fixes an issue where message objects were not translated (and
+ thus converted to a string) using the a provided ``translate``
+ function.
+
+- Fixed string interpolation issue where an expression immediately
+ succeeded by a right curly bracket would not parse.
+
+ This fixes issue #5.
+
+- Fixed error where ``tal:condition`` would be evaluated after
+ ``tal:repeat``.
+
+Features:
+
+- Python expression is now a TALES expression. That means that the
+ pipe operator can be used to chain two or more expressions in a
+ try-except sequence.
+
+ This behavior was ported from the 1.x series. Note that while it's
+ still possible to use the pipe character ("|") in an expression, it
+ must now be escaped.
+
+- The template cache can now be shared by multiple processes.
+
+
+2.0-rc3 (2011-03-02)
+--------------------
+
+Bugfixes:
+
+- Fixed ``atexit`` handler.
+
+ This fixes issue #3.
+
+- If a cache directory is specified, it will now be used even when not
+ in debug mode.
+
+- Allow "comment" attribute in the TAL namespace.
+
+ This fixes an issue in the sense that the reference engine allows
+ any attribute within the TAL namespace. However, only "comment" is
+ in common use.
+
+- The template constructor now accepts a flag ``debug`` which puts the
+ template *instance* into debug-mode regardless of the global
+ setting.
+
+ This fixes issue #1.
+
+Features:
+
+- Added exception handler for exceptions raised while evaluating an
+ expression.
+
+ This handler raises (or attempts to) a new exception of the type
+ ``RenderError``, with an additional base class of the original
+ exception class. The string value of the exception is a formatted
+ error message which includes the expression that caused the
+ exception.
+
+ If we are unable to create the exception class, the original
+ exception is re-raised.
+
+2.0-rc2 (2011-02-28)
+--------------------
+
+- Fixed upload issue.
+
+2.0-rc1 (2011-02-28)
+--------------------
+
+- Initial public release. See documentation for what's new in this
+ series.
diff --git a/lib/Chameleon-2.9.2/COPYRIGHT.txt b/lib/Chameleon-2.9.2/COPYRIGHT.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/COPYRIGHT.txt
@@ -0,0 +1,7 @@
+Copyright (c) 2011 Malthe Borch and Contributors. All Rights Reserved.
+
+Portions (c) Zope Foundation and contributors (http://www.zope.org/).
+
+Portions (c) Edgewall Software.
+
+Portions (c) 2008 Armin Ronacher.
diff --git a/lib/Chameleon-2.9.2/LICENSE.txt b/lib/Chameleon-2.9.2/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/LICENSE.txt
@@ -0,0 +1,185 @@
+The majority of the code in Chameleon is supplied under this license:
+
+ A copyright notice accompanies this license document that identifies
+ the copyright holders.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions in source code must retain the accompanying
+ copyright notice, this list of conditions, and the following
+ disclaimer.
+
+ 2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ 3. Names of the copyright holders must not be used to endorse or
+ promote products derived from this software without prior
+ written permission from the copyright holders.
+
+ 4. If any files are modified, you must cause the modified files to
+ carry prominent notices stating that you changed the files and
+ the date of any change.
+
+ Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND
+ ANY EXPRESSED 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 COPYRIGHT
+ HOLDERS 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.
+
+Portions of the code in Chameleon are supplied under the ZPL (headers
+within individiual files indicate that these portions are licensed
+under the ZPL):
+
+ Zope Public License (ZPL) Version 2.1
+ -------------------------------------
+
+ A copyright notice accompanies this license document that
+ identifies the copyright holders.
+
+ This license has been certified as open source. It has also
+ been designated as GPL compatible by the Free Software
+ Foundation (FSF).
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the
+ following conditions are met:
+
+ 1. Redistributions in source code must retain the
+ accompanying copyright notice, this list of conditions,
+ and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Names of the copyright holders must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from the copyright
+ holders.
+
+ 4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use
+ Servicemarks (sm) or Trademarks (tm) of the copyright
+ holders. Use of them is covered by separate agreement
+ with the copyright holders.
+
+ 5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+ Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+ AND ANY EXPRESSED 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 COPYRIGHT HOLDERS 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.
+
+Portions of the code in Chameleon are supplied under the BSD license
+(headers within individiual files indicate that these portions are
+licensed under this license):
+
+ 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.
+
+
+Portions of the code in Chameleon are supplied under the Python
+License (headers within individiual files indicate that these portions
+are licensed under this license):
+
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+ --------------------------------------------
+
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
+ otherwise using this software ("Python") in source or binary form and
+ its associated documentation.
+
+ 2. Subject to the terms and conditions of this License Agreement, PSF
+ hereby grants Licensee a nonexclusive, royalty-free, world-wide
+ license to reproduce, analyze, test, perform and/or display publicly,
+ prepare derivative works, distribute, and otherwise use Python
+ alone or in any derivative version, provided, however, that PSF's
+ License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
+ 2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved"
+ are retained in Python alone or in any derivative version prepared
+ by Licensee.
+
+ 3. In the event Licensee prepares a derivative work that is based on
+ or incorporates Python or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python.
+
+ 4. PSF is making Python available to Licensee on an "AS IS"
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+ 6. This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+
+ 7. Nothing in this License Agreement shall be deemed to create any
+ relationship of agency, partnership, or joint venture between PSF and
+ Licensee. This License Agreement does not grant permission to use PSF
+ trademarks or trade name in a trademark sense to endorse or promote
+ products or services of Licensee, or any third party.
+
+ 8. By copying, installing or otherwise using Python, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
diff --git a/lib/Chameleon-2.9.2/Makefile b/lib/Chameleon-2.9.2/Makefile
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/Makefile
@@ -0,0 +1,89 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS = docs
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS)
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Chameleon.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Chameleon.qhc"
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/lib/Chameleon-2.9.2/PKG-INFO b/lib/Chameleon-2.9.2/PKG-INFO
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/PKG-INFO
@@ -0,0 +1,1122 @@
+Metadata-Version: 1.1
+Name: Chameleon
+Version: 2.9.2
+Summary: Fast HTML/XML Template Compiler.
+Home-page: http://www.pagetemplates.org/
+Author: Malthe Borch
+Author-email: mborch at gmail.com
+License: BSD-like (http://repoze.org/license.html)
+Description: Overview
+ ========
+
+ Chameleon is an HTML/XML template engine for `Python
+ <http://www.python.org>`_. It uses the *page templates* language.
+
+ You can use it in any Python web application with just about any
+ version of Python (2.5 and up, including 3.x and `pypy
+ <http://pypy.org>`_).
+
+ Visit the `website <http://pagetemplates.org>`_ for more information
+ or the `documentation <http://pagetemplates.org/docs/latest/>`_.
+
+ License and Copyright
+ ---------------------
+
+ This software is made available as-is under a BSD-like license [1]_
+ (see included copyright notice).
+
+
+ Notes
+ -----
+
+ .. [1] This software is licensed under the `Repoze
+ <http://repoze.org/license.html>`_ license.
+
+
+ Changes
+ =======
+
+ 2.9.2 (2012-06-06)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed a PyPy incompatibility.
+
+ - Fixed issue #109 which caused testing failures on some platforms.
+
+ 2.9.1 (2012-06-01)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue #103. The ``tal:on-error`` statement now always adds an
+ explicit end-tag to the element, even with a substitution content of
+ nothing.
+
+ - Fixed issue #113. The ``tal:on-error`` statement now works correctly
+ also for dynamic attributes. That is, the fallback tag now includes
+ only static attributes.
+
+ - Fixed name error which prevented the benchmark from running
+ correctly.
+
+ Compatibility:
+
+ - Fixed deprecation warning on Python 3 for zope interface implements
+ declaration. This fixes issue #116.
+
+ 2.9.0 (2012-05-31)
+ ------------------
+
+ Features:
+
+ - The translation function now gets the ``econtext`` argument as the
+ value for ``context``. Note that historically, this was usually an
+ HTTP request which might provide language negotiation data through a
+ dictionary interface.
+ [alvinyue]
+
+ Bugfixes:
+
+ - Fixed import alias issue which would lead to a syntax error in
+ generated Python code. Fixes issue #114.
+
+ 2.8.5 (2012-05-02)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed minor installation issues on Python 2.5 and 3.
+ [ppaez]
+
+ - Ensure output is unicode even when trivial (an empty string).
+
+ 2.8.4 (2012-04-18)
+ ------------------
+
+ Features:
+
+ - In exception output, long filenames are now truncated to 60
+ characters of output, preventing line wrap which makes it difficult
+ to scan the exception output.
+
+ Bugfixes:
+
+ - Include filename and location in exception output for exceptions
+ raised during compilation.
+
+ - If a trivial translation substitution variable is given (i.e. an
+ empty string), simply ignore it. This fixes issue #106.
+
+ 2.8.3 (2012-04-16)
+ ------------------
+
+ Features:
+
+ - Log template source on debug-level before cooking.
+
+ - The `target_language` argument, if given, is now available as a
+ variable in templates.
+
+ 2.8.2 (2012-03-30)
+ ------------------
+
+ Features:
+
+ - Temporary caches used in debug mode are cleaned up eagerly, rather
+ than waiting for process termination.
+ [mitchellrj]
+
+ Bugfixes:
+
+ - The `index`, `start` and `end` methods on the TAL repeat object are
+ now callable. This fixes an incompatibility with ZPT.
+
+ - The loader now correctly handles absolute paths on Windows.
+ [rdale]
+
+ 2.8.1 (2012-03-29)
+ ------------------
+
+ Features:
+
+ - The exception formatter now lists errors in 'wrapping order'. This
+ means that the innermost, and presumably most relevant exception is
+ shown last.
+
+ Bugfixes:
+
+ - The exception formatter now correctly recognizes nested errors and
+ does not rewrap the dynamically generated exception class.
+
+ - The exception formatter now correctly sets the ``__module__``
+ attribute to that of the original exception class.
+
+ 2.8.0 (2012-02-29)
+ ------------------
+
+ Features:
+
+ - Added support for code blocks using the `<?python ... ?>` processing
+ instruction syntax.
+
+ The scope is name assignments is up until the nearest macro
+ definition, or the template itself if macros are not used.
+
+ Bugfixes:
+
+ - Fall back to the exception class' ``__new__`` method to safely
+ create an exception object that is not implemented in Python.
+
+ - The exception formatter now keeps track of already formatted
+ exceptions, and ignores them from further output.
+
+ 2.7.4 (2012-02-27)
+ ------------------
+
+ - The error handler now invokes the ``__init__`` method of
+ ``BaseException`` instead of the possibly overriden method (which
+ may take required arguments). This fixes issue #97.
+ [j23d, malthe]
+
+ 2.7.3 (2012-01-16)
+ ------------------
+
+ Bugfixes:
+
+ - The trim whitespace option now correctly trims actual whitespace to
+ a single character, appearing either to the left or to the right of
+ an element prefix or suffix string.
+
+ 2.7.2 (2012-01-08)
+ ------------------
+
+ Features:
+
+ - Added option ``trim_attribute_space`` that decides whether attribute
+ whitespace is stripped (at most down to a single space). This option
+ exists to provide compatibility with the reference
+ implementation. Fixes issue #85.
+
+ Bugfixes:
+
+ - Ignore unhashable builtins when generating a reverse builtin
+ map to quickly look up a builtin value.
+ [malthe]
+
+ - Apply translation mapping even when a translation function is not
+ available. This fixes issue #83.
+ [malthe]
+
+ - Fixed issue #80. The translation domain for a slot is defined by the
+ source document, i.e. the template providing the content for a slot
+ whether it be the default or provided through ``metal:fill-slot``.
+ [jcbrand]
+
+ - In certain circumstances, a Unicode non-breaking space character would cause
+ a define clause to fail to parse.
+
+ 2.7.1 (2011-12-29)
+ ------------------
+
+ Features:
+
+ - Enable expression interpolation in CDATA.
+
+ - The page template class now implements dictionary access to macros::
+
+ template[name]
+
+ This is a short-hand for::
+
+ template.macros[name]
+
+ Bugfixes:
+
+ - An invalid define clause would be silently ignored; we now raise a
+ language error exception. This fixes issue #79.
+
+ - Fixed regression where ``${...}`` interpolation expressions could
+ not span multiple lines. This fixes issue #77.
+
+ 2.7.0 (2011-12-13)
+ ------------------
+
+ Features:
+
+ - The ``load:`` expression now derives from the string expression such
+ that the ``${...}`` operator can be used for expression
+ interpolation.
+
+ - The ``load:`` expression now accepts asset specs; these are resolved
+ by the ``pkg_resources.resource_filename`` function::
+
+ <package_name>:<path>
+
+ An example from the test suite::
+
+ chameleon:tests/inputs/hello_world.pt
+
+ Bugfixes:
+
+ - If an attribute name for translation was not a valid Python
+ identifier, the compiler would generate invalid code. This has been
+ fixed, and the compiler now also throws an exception if an attribute
+ specification contains a comma. (Note that the only valid separator
+ character is the semicolon, when specifying attributes for
+ translation via the ``i18n:translate`` statement). This addresses
+ issue #76.
+
+ 2.6.2 (2011-12-08)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue where ``tal:on-error`` would not respect
+ ``tal:omit-tag`` or namespace elements which are omitted by default
+ (such as ``<tal:block />``).
+
+ - Fixed issue where ``macros`` attribute would not be available on
+ file-based templates due to incorrect initialization.
+
+ - The ``TryExcept`` and ``TryFinally`` AST nodes are not available on
+ Python 3.3. These have been aliased to ``Try``. This fixes issue
+ #75.
+
+ Features:
+
+ - The TAL repeat item now makes a security declaration that grants
+ access to unprotected subobjects on the Zope 2 platform::
+
+ __allow_access_to_unprotected_subobjects__ = True
+
+ This is required for legacy compatibility and does not affect other
+ environments.
+
+ - The template object now has a method ``write(body)`` which
+ explicitly decodes and cooks a string input.
+
+ - Added configuration option ``loader_class`` which sets the class
+ used to create the template loader object.
+
+ The class (essentially a callable) is created at template
+ construction time.
+
+ 2.6.1 (2011-11-30)
+ ------------------
+
+ Bugfixes:
+
+ - Decode HTML entities in expression interpolation strings. This fixes
+ issue #74.
+
+ - Allow ``xml`` and ``xmlns`` attributes on TAL, I18N and METAL
+ namespace elements. This fixes issue #73.
+
+ 2.6.0 (2011-11-24)
+ ------------------
+
+ Features:
+
+ - Added support for implicit translation:
+
+ The ``implicit_i18n_translate`` option enables implicit translation
+ of text. The ``implicit_i18n_attributes`` enables implicit
+ translation of attributes. The latter must be a set and for an
+ attribute to be implicitly translated, its lowercase string value
+ must be included in the set.
+
+ - Added option ``strict`` (enabled by default) which decides whether
+ expressions are required to be valid at compile time. That is, if
+ not set, an exception is only raised for an invalid expression at
+ evaluation time.
+
+ - An expression error now results in an exception only if the
+ expression is attempted evaluated during a rendering.
+
+ - Added a configuration option ``prepend_relative_search_path`` which
+ decides whether the path relative to a file-based template is
+ prepended to the load search path. The default is ``True``.
+
+ - Added a configuration option ``search_path`` to the file-based
+ template class, which adds additional paths to the template load
+ instance bound to the ``load:`` expression. The option takes a
+ string path or an iterable yielding string paths. The default value
+ is the empty set.
+
+ Bugfixes:
+
+ - Exception instances now support pickle/unpickle.
+
+ - An attributes in i18n:attributes no longer needs to match an
+ existing or dynamic attribute in order to appear in the
+ element. This fixes issue #66.
+
+ 2.5.3 (2011-10-23)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue where a nested macro slot definition would fail even
+ though there existed a parent macro definition. This fixes issue
+ #69.
+
+ 2.5.2 (2011-10-12)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue where technically invalid input would result in a
+ compiler error.
+
+ Features:
+
+ - The markup class now inherits from the unicode string type such that
+ it's compatible with the string interface.
+
+ 2.5.1 (2011-09-29)
+ ------------------
+
+ Bugfixes:
+
+ - The symbol names "convert", "decode" and "translate" are now no
+ longer set as read-only *compiler internals*. This fixes issue #65.
+
+ - Fixed an issue where a macro extension chain nested two levels (a
+ template uses a macro that extends a macro) would lose the middle
+ slot definitions if slots were defined nested.
+
+ The compiler now throws an error if a nested slot definition is used
+ outside a macro extension context.
+
+ 2.5.0 (2011-09-23)
+ ------------------
+
+ Features:
+
+ - An expression type ``structure:`` is now available which wraps the
+ expression result as *structure* such that it is not escaped on
+ insertion, e.g.::
+
+ <div id="content">
+ ${structure: context.body}
+ </div>
+
+ This also means that the ``structure`` keyword for ``tal:content``
+ and ``tal:replace`` now has an alternative spelling via the
+ expression type ``structure:``.
+
+ - The string-based template constructor now accepts encoded input.
+
+ 2.4.6 (2011-09-23)
+ ------------------
+
+ Bugfixes:
+
+ - The ``tal:on-error`` statement should catch all exceptions.
+
+ - Fixed issue that would prevent escaping of interpolation expression
+ values appearing in text.
+
+ 2.4.5 (2011-09-21)
+ ------------------
+
+ Bugfixes:
+
+ - The ``tal:on-error`` handler should have a ``error`` variable
+ defined that has the value of the exception thrown.
+
+ - The ``tal:on-error`` statement is a substitution statement and
+ should support the "text" and "structure" insertion methods.
+
+ 2.4.4 (2011-09-15)
+ ------------------
+
+ Bugfixes:
+
+ - An encoding specified in the XML document preamble is now read and
+ used to decode the template input to unicode. This fixes issue #55.
+
+ - Encoded expression input on Python 3 is now correctly
+ decoded. Previously, the string representation output would be
+ included instead of an actually decoded string.
+
+ - Expression result conversion steps are now correctly included in
+ error handling such that the exception output points to the
+ expression location.
+
+ 2.4.3 (2011-09-13)
+ ------------------
+
+ Features:
+
+ - When an encoding is provided, pass the 'ignore' flag to avoid
+ decoding issues with bad input.
+
+ Bugfixes:
+
+ - Fixed pypy compatibility issue (introduced in previous release).
+
+ 2.4.2 (2011-09-13)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue in the compiler where an internal variable (such as a
+ translation default value) would be cached, resulting in variable
+ scope corruption (see issue #49).
+
+ 2.4.1 (2011-09-08)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue where a default value for an attribute would
+ sometimes spill over into another attribute.
+
+ - Fixed issue where the use of the ``default`` name in an attribute
+ interpolation expression would print the attribute value. This is
+ unexpected, because it's an expression, not a static text suitable
+ for output. An attribute value of ``default`` now correctly drops
+ the attribute.
+
+ 2.4.0 (2011-08-22)
+ ------------------
+
+ Features:
+
+ - Added an option ``boolean_attributes`` to evaluate and render a
+ provided set of attributes using a boolean logic: if the attribute
+ is a true value, the value will be the attribute name, otherwise the
+ attribute is dropped.
+
+ In the reference implementation, the following attributes are
+ configured as boolean values when the template is rendered in
+ HTML-mode::
+
+ "compact", "nowrap", "ismap", "declare", "noshade",
+ "checked", "disabled", "readonly", "multiple", "selected",
+ "noresize", "defer"
+
+ Note that in Chameleon, these attributes must be manually provided.
+
+ Bugfixes:
+
+ - The carriage return character (used on Windows platforms) would
+ incorrectly be included in Python comments.
+
+ It is now replaced with a line break.
+
+ This fixes issue #44.
+
+ 2.3.8 (2011-08-19)
+ ------------------
+
+ - Fixed import error that affected Python 2.5 only.
+
+ 2.3.7 (2011-08-19)
+ ------------------
+
+ Features:
+
+ - Added an option ``literal_false`` that disables the default behavior
+ of dropping an attribute for a value of ``False`` (in addition to
+ ``None``). This modified behavior is the behavior exhibited in
+ reference implementation.
+
+ Bugfixes:
+
+ - Undo attribute special HTML attribute behavior (see previous
+ release).
+
+ This turned out not to be a compatible behavior; rather, boolean
+ values should simply be coerced to a string.
+
+ Meanwhile, the reference implementation does support an HTML mode in
+ which the special attribute behavior is exhibited.
+
+ We do not currently support this mode.
+
+ 2.3.6 (2011-08-18)
+ ------------------
+
+ Features:
+
+ - Certain HTML attribute names now have a special behavior for a
+ attribute value of ``True`` (or ``default`` if no default is
+ defined). For these attributes, this return value will result in the
+ name being printed as the value::
+
+ <input type="input" tal:attributes="checked True" />
+
+ will be rendered as::
+
+ <input type="input" checked="checked" />
+
+ This behavior is compatible with the reference implementation.
+
+ 2.3.5 (2011-08-18)
+ ------------------
+
+ Features:
+
+ - Added support for the set operator (``{item, item, ...}``).
+
+ Bugfixes:
+
+ - If macro is defined on the same element as a translation name, this
+ no longer results in a "translation name not allowed outside
+ translation" error. This fixes issue #43.
+
+ - Attribute fallback to dictionary lookup now works on multiple items
+ (e.g. ``d1.d2.d2``). This fixes issue #42.
+
+ 2.3.4 (2011-08-16)
+ ------------------
+
+ Features:
+
+ - When inserting content in either attributes or text, a value of
+ ``True`` (like ``False`` and ``None``) will result in no
+ action.
+
+ - Use statically assigned variables for ``"attrs"`` and
+ ``"default"``. This change yields a performance improvement of
+ 15-20%.
+
+ - The template loader class now accepts an optional argument
+ ``default_extension`` which accepts a filename extension which will
+ be appended to the filename if there's not already an extension.
+
+ Bugfixes:
+
+ - The default symbol is now ``True`` for an attribute if the attribute
+ default is not provided. Note that the result is that the attribute
+ is dropped. This fixes issue #41.
+
+ - Fixed an issue where assignment to a variable ``"type"`` would
+ fail. This fixes issue #40.
+
+ - Fixed an issue where an (unsuccesful) assignment for a repeat loop
+ to a compiler internal name would not result in an error.
+
+ - If the translation function returns the identical object, manually
+ coerce it to string. This fixes a compatibility issue with
+ translation functions which do not convert non-string objects to a
+ string value, but simply return them unchanged.
+
+ 2.3.3 (2011-08-15)
+ ------------------
+
+ Features:
+
+ - The ``load:`` expression now passes the initial keyword arguments to
+ its template loader (e.g. ``auto_reload`` and ``encoding``).
+
+ - In the exception output, string variable values are now limited to a
+ limited output of characters, single line only.
+
+ Bugfixes:
+
+ - Fixed horizontal alignment of exception location info
+ (i.e. 'String:', 'Filename:' and 'Location:') such that they match
+ the template exception formatter.
+
+ 2.3.2 (2011-08-11)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue where i18n:domain would not be inherited through macros
+ and slots. This fixes issue #37.
+
+ 2.3.1 (2011-08-11)
+ ------------------
+
+ Features:
+
+ - The ``Builtin`` node type may now be used to represent any Python
+ local or global name. This allows expression compilers to refer to
+ e.g. ``get`` or ``getitem``, or to explicit require a builtin object
+ such as one from the ``extra_builtins`` dictionary.
+
+ Bugfixes:
+
+ - Builtins which are not explicitly disallowed may now be redefined
+ and used as variables (e.g. ``nothing``).
+
+ - Fixed compiler issue with circular node annotation loop.
+
+ 2.3 (2011-08-10)
+ ----------------
+
+ Features:
+
+ - Added support for the following syntax to disable inline evaluation
+ in a comment:
+
+ <!--? comment appears verbatim (no ${...} evaluation) -->
+
+ Note that the initial question mark character (?) will be omitted
+ from output.
+
+ - The parser now accepts '<' and '>' in attributes. Note that this is
+ invalid markup. Previously, the '<' would not be accepted as a valid
+ attribute value, but this would result in an 'unexpected end tag'
+ error elsewhere. This fixes issue #38.
+
+ - The expression compiler now provides methods ``assign_text`` and
+ ``assign_value`` such that a template engine might configure this
+ value conversion to support e.g. encoded strings.
+
+ Note that currently, the only client for the ``assign_text`` method
+ is the string expression type.
+
+ - Enable template loader for string-based template classes. Note that
+ the ``filename`` keyword argument may be provided on initialization
+ to identify the template source by filename. This fixes issue #36.
+
+ - Added ``extra_builtins`` option to the page template class. These
+ builtins are added to the default builtins dictionary at cook time
+ and may be provided at initialization using the ``extra_builtins``
+ keyword argument.
+
+ Bugfixes:
+
+ - If a translation domain is set for a fill slot, use this setting
+ instead of the macro template domain.
+
+ - The Python expression compiler now correctly decodes HTML entities
+ ``'gt'`` and ``'lt'``. This fixes issue #32.
+
+ - The string expression compiler now correctly handles encoded text
+ (when support for encoded strings is enabled). This fixes issue #35.
+
+ - Fixed an issue where setting the ``filename`` attribute on a
+ file-based template would not automatically cause an invalidation.
+
+ - Exceptions raised by Chameleon can now be copied via
+ ``copy.copy``. This fixes issue #36.
+ [leorochael]
+
+ - If copying the exception fails in the exception handler, simply
+ re-raise the original exception and log a warning.
+
+ 2.2 (2011-07-28)
+ ----------------
+
+ Features:
+
+ - Added new expression type ``load:`` that allows loading a
+ template. Both relative and absolute paths are supported. If the
+ path given is relative, then it will be resolved with respect to the
+ directory of the template.
+
+ - Added support for dynamic evaluation of expressions.
+
+ Note that this is to support legacy applications. It is not
+ currently wired into the provided template classes.
+
+ - Template classes now have a ``builtins`` attribute which may be used
+ to define built-in variables always available in the template
+ variable scope.
+
+ Incompatibilities:
+
+ - The file-based template class no longer accepts a parameter
+ ``loader``. This parameter would be used to load a template from a
+ relative path, using a ``find(filename)`` method. This was however,
+ undocumented, and probably not very useful since we have the
+ ``TemplateLoader`` mechanism already.
+
+ - The compiled template module now contains an ``initialize`` function
+ which takes values that map to the template builtins. The return
+ value of this function is a dictionary that contains the render
+ functions.
+
+ Bugfixes:
+
+ - The file-based template class no longer verifies the existance of a
+ template file (using ``os.lstat``). This now happens implicitly if
+ eager parsing is enabled, or otherwise when first needed (e.g. at
+ render time).
+
+ This is classified as a bug fix because the previous behavior was
+ probably not what you'd expect, especially if an application
+ initializes a lot of templates without needing to render them
+ immediately.
+
+ 2.1.1 (2011-07-28)
+ ------------------
+
+ Features:
+
+ - Improved exception display. The expression string is now shown in
+ the context of the original source (if available) with a marker
+ string indicating the location of the expression in the template
+ source.
+
+ Bugfixes:
+
+ - The ``structure`` insertion mode now correctly decodes entities for
+ any expression type (including ``string:``). This fixes issue #30.
+
+ - Don't show internal variables in the exception formatter variable
+ listing.
+
+ 2.1 (2011-07-25)
+ ----------------
+
+ Features:
+
+ - Expression interpolation (using the ``${...}`` operator and
+ previously also ``$identifier``) now requires braces everywhere
+ except inside the ``string:`` expression type.
+
+ This change is motivated by a number of legacy templates in which
+ the interpolation format without braces ``$identifier`` appears as
+ text.
+
+ 2.0.2 (2011-07-25)
+ ------------------
+
+ Bugfixes:
+
+ - Don't use dynamic variable scope for lambda-scoped variables (#27).
+
+ - Avoid duplication of exception class and message in traceback.
+
+ - Fixed issue where a ``metal:fill-slot`` would be ignored if a macro
+ was set to be used on the same element (#16).
+
+ 2.0.1 (2011-07-23)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue where global variable definition from macro slots would
+ fail (they would instead be local). This also affects error
+ reporting from inside slots because this would be recorded
+ internally as a global.
+
+ - Fixed issue with template cache digest (used for filenames); modules
+ are now invalidated whenever any changes are made to the
+ distribution set available (packages on ``sys.path``).
+
+ - Fixed exception handler to better let exceptions propagate through
+ the renderer.
+
+ - The disk-based module compiler now mangles template source filenames
+ such that the output Python module is valid and at root level (dots
+ and hyphens are replaced by an underscore). This fixes issue #17.
+
+ - Fixed translations (i18n) on Python 2.5.
+
+ 2.0 (2011-07-14)
+ ----------------
+
+ - Point release.
+
+ 2.0-rc14 (2011-07-13)
+ ---------------------
+
+ Bugfixes:
+
+ - The tab character (``\t``) is now parsed correctly when used inside
+ tags.
+
+ Features:
+
+ - The ``RepeatDict`` class now works as a proxy behind a seperate
+ dictionary instance.
+
+ - Added template constructor option ``keep_body`` which is a flag
+ (also available as a class attribute) that controls whether to save
+ the template body input in the ``body`` attribute.
+
+ This is disabled by default, unless debug-mode is enabled.
+
+ - The page template loader class now accepts an optional ``formats``
+ argument which can be used to select an alternative template class.
+
+ 2.0-rc13 (2011-07-07)
+ ---------------------
+
+ Bugfixes:
+
+ - The backslash character (followed by optional whitespace and a line
+ break) was not correctly interpreted as a continuation for Python
+ expressions.
+
+ Features:
+
+ - The Python expression implementation is now more flexible for
+ external subclassing via a new ``parse`` method.
+
+ 2.0-rc12 (2011-07-04)
+ ---------------------
+
+ Bugfixes:
+
+ - Initial keyword arguments passed to a template now no longer "leak"
+ into the template variable space after a macro call.
+
+ - An unexpected end tag is now an unrecoverable error.
+
+ Features:
+
+ - Improve exception output.
+
+ 2.0-rc11 (2011-05-26)
+ ---------------------
+
+ Bugfixes:
+
+ - Fixed issue where variable names that begin with an underscore were
+ seemingly allowed, but their use resulted in a compiler error.
+
+ Features:
+
+ - Template variable names are now allowed to be prefixed with a single
+ underscore, but not two or more (reserved for internal use).
+
+ Examples of valid names::
+
+ item
+ ITEM
+ _item
+ camelCase
+ underscore_delimited
+ help
+
+ - Added support for Genshi's comment "drop" syntax::
+
+ <!--! This comment will be dropped -->
+
+ Note the additional exclamation (!) character.
+
+ This fixes addresses issue #10.
+
+ 2.0-rc10 (2011-05-24)
+ ---------------------
+
+ Bugfixes:
+
+ - The ``tal:attributes`` statement now correctly operates
+ case-insensitive. The attribute name given in the statement will
+ replace an existing attribute with the same name, without respect to
+ case.
+
+ Features:
+
+ - Added ``meta:interpolation`` statement to control expression
+ interpolation setting.
+
+ Strings that disable the setting: ``"off"`` and ``"false"``.
+ Strings that enable the setting: ``"on"`` and ``"true"``.
+
+ - Expression interpolation now works inside XML comments.
+
+ 2.0-rc9 (2011-05-05)
+ --------------------
+
+ Features:
+
+ - Better debugging support for string decode and conversion. If a
+ naive join fails, each element in the output will now be attempted
+ coerced to unicode to try and trigger the failure near to the bad
+ string.
+
+ 2.0-rc8 (2011-04-11)
+ --------------------
+
+ Bugfixes:
+
+ - If a macro defines two slots with the same name, a caller will now
+ fill both with a single usage.
+
+ - If a valid of ``None`` is provided as the translation function
+ argument, we now fall back to the class default.
+
+ 2.0-rc7 (2011-03-29)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed issue with Python 2.5 compatibility AST. This affected at
+ least PyPy 1.4.
+
+ Features:
+
+ - The ``auto_reload`` setting now defaults to the class value; the
+ base template class gives a default value of
+ ``chameleon.config.AUTO_RELOAD``. This change allows a subclass to
+ provide a custom default value (such as an application-specific
+ debug mode setting).
+
+
+ 2.0-rc6 (2011-03-19)
+ --------------------
+
+ Features:
+
+ - Added support for ``target_language`` keyword argument to render
+ method. If provided, the argument will be curried onto the
+ translation function.
+
+ Bugfixes:
+
+ - The HTML entities 'lt', 'gt' and 'quot' appearing inside content
+ subtition expressions are now translated into their native character
+ values. This fixes an issue where you could not dynamically create
+ elements using the ``structure`` (which is possible in ZPT). The
+ need to create such structure stems from the lack of an expression
+ interpolation operator in ZPT.
+
+ - Fixed duplicate file pointer issue with test suite (affected Windows
+ platforms only). This fixes issue #9.
+ [oliora]
+
+ - Use already open file using ``os.fdopen`` when trying to write out
+ the module source. This fixes LP #731803.
+
+
+ 2.0-rc5 (2011-03-07)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed a number of issues concerning the escaping of attribute
+ values:
+
+ 1) Static attribute values are now included as they appear in the
+ source.
+
+ This means that invalid attribute values such as ``"true &&
+ false"`` are now left alone. It's not the job of the template
+ engine to correct such markup, at least not in the default mode
+ of operation.
+
+ 2) The string expression compiler no longer unescapes
+ values. Instead, this is left to each expression
+ compiler. Currently only the Python expression compiler unescapes
+ its input.
+
+ 3) The dynamic escape code sequence now correctly only replaces
+ ampersands that are part of an HTML escape format.
+
+ Imports:
+
+ - The page template classes and the loader class can now be imported
+ directly from the ``chameleon`` module.
+
+ Features:
+
+ - If a custom template loader is not provided, relative paths are now
+ resolved using ``os.abspath`` (i.e. to the current working
+ directory).
+
+ - Absolute paths are normalized using ``os.path.normpath`` and
+ ``os.path.expanduser``. This ensures that all paths are kept in
+ their "canonical" form.
+
+
+ 2.0-rc4 (2011-03-03)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed an issue where the output of an end-to-end string expression
+ would raise an exception if the expression evaluated to ``None`` (it
+ should simply output nothing).
+
+ - The ``convert`` function (which is configurable on the template
+ class level) now defaults to the ``translate`` function (at
+ run-time).
+
+ This fixes an issue where message objects were not translated (and
+ thus converted to a string) using the a provided ``translate``
+ function.
+
+ - Fixed string interpolation issue where an expression immediately
+ succeeded by a right curly bracket would not parse.
+
+ This fixes issue #5.
+
+ - Fixed error where ``tal:condition`` would be evaluated after
+ ``tal:repeat``.
+
+ Features:
+
+ - Python expression is now a TALES expression. That means that the
+ pipe operator can be used to chain two or more expressions in a
+ try-except sequence.
+
+ This behavior was ported from the 1.x series. Note that while it's
+ still possible to use the pipe character ("|") in an expression, it
+ must now be escaped.
+
+ - The template cache can now be shared by multiple processes.
+
+
+ 2.0-rc3 (2011-03-02)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed ``atexit`` handler.
+
+ This fixes issue #3.
+
+ - If a cache directory is specified, it will now be used even when not
+ in debug mode.
+
+ - Allow "comment" attribute in the TAL namespace.
+
+ This fixes an issue in the sense that the reference engine allows
+ any attribute within the TAL namespace. However, only "comment" is
+ in common use.
+
+ - The template constructor now accepts a flag ``debug`` which puts the
+ template *instance* into debug-mode regardless of the global
+ setting.
+
+ This fixes issue #1.
+
+ Features:
+
+ - Added exception handler for exceptions raised while evaluating an
+ expression.
+
+ This handler raises (or attempts to) a new exception of the type
+ ``RenderError``, with an additional base class of the original
+ exception class. The string value of the exception is a formatted
+ error message which includes the expression that caused the
+ exception.
+
+ If we are unable to create the exception class, the original
+ exception is re-raised.
+
+ 2.0-rc2 (2011-02-28)
+ --------------------
+
+ - Fixed upload issue.
+
+ 2.0-rc1 (2011-02-28)
+ --------------------
+
+ - Initial public release. See documentation for what's new in this
+ series.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
diff --git a/lib/Chameleon-2.9.2/README.rst b/lib/Chameleon-2.9.2/README.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/README.rst
@@ -0,0 +1,25 @@
+Overview
+========
+
+Chameleon is an HTML/XML template engine for `Python
+<http://www.python.org>`_. It uses the *page templates* language.
+
+You can use it in any Python web application with just about any
+version of Python (2.5 and up, including 3.x and `pypy
+<http://pypy.org>`_).
+
+Visit the `website <http://pagetemplates.org>`_ for more information
+or the `documentation <http://pagetemplates.org/docs/latest/>`_.
+
+License and Copyright
+---------------------
+
+This software is made available as-is under a BSD-like license [1]_
+(see included copyright notice).
+
+
+Notes
+-----
+
+.. [1] This software is licensed under the `Repoze
+ <http://repoze.org/license.html>`_ license.
diff --git a/lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py b/lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py
@@ -0,0 +1,128 @@
+#!/usr/bin/python2
+
+"""
+Benchmark for test the performance of Chameleon page template engine.
+"""
+
+__author__ = "mborch at gmail.com (Malthe Borch)"
+
+# Python imports
+import os
+import sys
+import optparse
+import time
+
+# Local imports
+import util
+
+
+def relative(*args):
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), *args)
+
+sys.path.insert(0, relative('..', 'src'))
+
+# Chameleon imports
+from chameleon import PageTemplate
+
+
+LOREM_IPSUM = """Quisque lobortis hendrerit posuere. Curabitur
+aliquet consequat sapien molestie pretium. Nunc adipiscing luc
+tus mi, viverra porttitor lorem vulputate et. Ut at purus sem,
+sed tincidunt ante. Vestibulum ante ipsum primis in faucibus
+orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar
+sodales justo at congue. Praesent aliquet facilisis nisl a
+molestie. Sed tempus nisl ut augue eleifend tincidunt. Sed a
+lacinia nulla. Cras tortor est, mollis et consequat at,
+vulputate et orci. Nulla sollicitudin"""
+
+BASE_TEMPLATE = '''
+<tal:macros condition="False">
+ <table metal:define-macro="table">
+ <tr tal:repeat="row table">
+ <td tal:repeat="col row">${col}</td>
+ </tr>
+ </table>
+ <img metal:define-macro="img" src="${src}" alt="${alt}" />
+</tal:macros>
+<html metal:define-macro="master">
+ <head><title>${title.strip()}</title></head>
+ <body metal:define-slot="body" />
+</html>
+'''
+
+PAGE_TEMPLATE = '''
+<html metal:define-macro="master" metal:extend-macro="base.macros['master']">
+<body metal:fill-slot="body">
+<table metal:use-macro="base.macros['table']" />
+images:
+<tal:images repeat="nr xrange(img_count)">
+ <img tal:define="src '/foo/bar/baz.png';
+ alt 'no image :o'"
+ metal:use-macro="base.macros['img']" />
+</tal:images>
+<metal:body define-slot="body" />
+<p tal:repeat="nr paragraphs">${lorem}</p>
+<table metal:use-macro="base.macros['table']" />
+</body>
+</html>
+'''
+
+CONTENT_TEMPLATE = '''
+<html metal:use-macro="page.macros['master']">
+<span metal:define-macro="fun1">fun1</span>
+<span metal:define-macro="fun2">fun2</span>
+<span metal:define-macro="fun3">fun3</span>
+<span metal:define-macro="fun4">fun4</span>
+<span metal:define-macro="fun5">fun5</span>
+<span metal:define-macro="fun6">fun6</span>
+<body metal:fill-slot="body">
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Nam laoreet justo in velit faucibus lobortis. Sed dictum sagittis
+volutpat. Sed adipiscing vestibulum consequat. Nullam laoreet, ante
+nec pretium varius, libero arcu porttitor orci, id cursus odio nibh
+nec leo. Vestibulum dapibus pellentesque purus, sed bibendum tortor
+laoreet id. Praesent quis sodales ipsum. Fusce ut ligula sed diam
+pretium sagittis vel at ipsum. Nulla sagittis sem quam, et volutpat
+velit. Fusce dapibus ligula quis lectus ultricies tempor. Pellente</p>
+<span metal:use-macro="template.macros['fun1']" />
+<span metal:use-macro="template.macros['fun2']" />
+<span metal:use-macro="template.macros['fun3']" />
+<span metal:use-macro="template.macros['fun4']" />
+<span metal:use-macro="template.macros['fun5']" />
+<span metal:use-macro="template.macros['fun6']" />
+</body>
+</html>
+'''
+
+
+def test_mako(count):
+ template = PageTemplate(CONTENT_TEMPLATE)
+ base = PageTemplate(BASE_TEMPLATE)
+ page = PageTemplate(PAGE_TEMPLATE)
+
+ table = [xrange(150) for i in xrange(150)]
+ paragraphs = xrange(50)
+ title = 'Hello world!'
+
+ times = []
+ for i in range(count):
+ t0 = time.time()
+ data = template.render(
+ table=table, paragraphs=paragraphs,
+ lorem=LOREM_IPSUM, title=title,
+ img_count=50,
+ base=base,
+ page=page,
+ )
+ t1 = time.time()
+ times.append(t1-t0)
+ return times
+
+if __name__ == "__main__":
+ parser = optparse.OptionParser(
+ usage="%prog [options]",
+ description=("Test the performance of Chameleon templates."))
+ util.add_standard_options_to(parser)
+ (options, args) = parser.parse_args()
+
+ util.run_benchmark(options, options.num_runs, test_mako)
diff --git a/lib/Chameleon-2.9.2/benchmarks/bm_mako.py b/lib/Chameleon-2.9.2/benchmarks/bm_mako.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/benchmarks/bm_mako.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+
+"""
+Benchmark for test the performance of Mako templates engine.
+Includes:
+ -two template inherences
+ -HTML escaping, XML escaping, URL escaping, whitespace trimming
+ -function defitions and calls
+ -forloops
+"""
+
+__author__ = "virhilo at gmail.com (Lukasz Fidosz)"
+
+# Python imports
+import os
+import sys
+import optparse
+import time
+
+# Local imports
+import util
+
+def relative(*args):
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), *args)
+
+sys.path.insert(0, relative('..', 'lib'))
+
+# Mako imports
+from mako.template import Template
+from mako.lookup import TemplateLookup
+
+
+LOREM_IPSUM = """Quisque lobortis hendrerit posuere. Curabitur
+aliquet consequat sapien molestie pretium. Nunc adipiscing luc
+tus mi, viverra porttitor lorem vulputate et. Ut at purus sem,
+sed tincidunt ante. Vestibulum ante ipsum primis in faucibus
+orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar
+sodales justo at congue. Praesent aliquet facilisis nisl a
+molestie. Sed tempus nisl ut augue eleifend tincidunt. Sed a
+lacinia nulla. Cras tortor est, mollis et consequat at,
+vulputate et orci. Nulla sollicitudin"""
+
+BASE_TEMPLATE = """
+<%def name="render_table(table)">
+ <table>
+ % for row in table:
+ <tr>
+ % for col in row:
+ <td>${col|h}</td>
+ % endfor
+ </tr>
+ % endfor
+ </table>
+</%def>
+<%def name="img(src, alt)">
+ <img src="${src|u}" alt="${alt}" />
+</%def>
+<html>
+ <head><title>${title|h,trim}</title></head>
+ <body>
+ ${next.body()}
+ </body>
+<html>
+"""
+
+PAGE_TEMPLATE = """
+<%inherit file="base.mako"/>
+<table>
+ % for row in table:
+ <tr>
+ % for col in row:
+ <td>${col}</td>
+ % endfor
+ </tr>
+ % endfor
+</table>
+% for nr in xrange(img_count):
+ ${parent.img('/foo/bar/baz.png', 'no image :o')}
+% endfor
+${next.body()}
+% for nr in paragraphs:
+ <p>${lorem|x}</p>
+% endfor
+${parent.render_table(table)}
+"""
+
+CONTENT_TEMPLATE = """
+<%inherit file="page.mako"/>
+<%def name="fun1()">
+ <span>fun1</span>
+</%def>
+<%def name="fun2()">
+ <span>fun2</span>
+</%def>
+<%def name="fun3()">
+ <span>foo3</span>
+</%def>
+<%def name="fun4()">
+ <span>foo4</span>
+</%def>
+<%def name="fun5()">
+ <span>foo5</span>
+</%def>
+<%def name="fun6()">
+ <span>foo6</span>
+</%def>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Nam laoreet justo in velit faucibus lobortis. Sed dictum sagittis
+volutpat. Sed adipiscing vestibulum consequat. Nullam laoreet, ante
+nec pretium varius, libero arcu porttitor orci, id cursus odio nibh
+nec leo. Vestibulum dapibus pellentesque purus, sed bibendum tortor
+laoreet id. Praesent quis sodales ipsum. Fusce ut ligula sed diam
+pretium sagittis vel at ipsum. Nulla sagittis sem quam, et volutpat
+velit. Fusce dapibus ligula quis lectus ultricies tempor. Pellente</p>
+${fun1()}
+${fun2()}
+${fun3()}
+${fun4()}
+${fun5()}
+${fun6()}
+"""
+
+
+def test_mako(count):
+
+ lookup = TemplateLookup()
+ lookup.put_string('base.mako', BASE_TEMPLATE)
+ lookup.put_string('page.mako', PAGE_TEMPLATE)
+
+ template = Template(CONTENT_TEMPLATE, lookup=lookup)
+
+ table = [xrange(150) for i in xrange(150)]
+ paragraphs = xrange(50)
+ title = 'Hello world!'
+
+ times = []
+ for i in range(count):
+ t0 = time.time()
+ data = template.render(table=table, paragraphs=paragraphs,
+ lorem=LOREM_IPSUM, title=title,
+ img_count=50)
+ t1 = time.time()
+ times.append(t1-t0)
+ return times
+
+if __name__ == "__main__":
+ parser = optparse.OptionParser(
+ usage="%prog [options]",
+ description=("Test the performance of Mako templates."))
+ util.add_standard_options_to(parser)
+ (options, args) = parser.parse_args()
+
+ util.run_benchmark(options, options.num_runs, test_mako)
diff --git a/lib/Chameleon-2.9.2/benchmarks/util.py b/lib/Chameleon-2.9.2/benchmarks/util.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/benchmarks/util.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+"""Utility code for benchmark scripts."""
+
+__author__ = "collinwinter at google.com (Collin Winter)"
+
+import math
+import operator
+
+
+def run_benchmark(options, num_runs, bench_func, *args):
+ """Run the given benchmark, print results to stdout.
+
+ Args:
+ options: optparse.Values instance.
+ num_runs: number of times to run the benchmark
+ bench_func: benchmark function. `num_runs, *args` will be passed to this
+ function. This should return a list of floats (benchmark execution
+ times).
+ """
+ if options.profile:
+ import cProfile
+ prof = cProfile.Profile()
+ prof.runcall(bench_func, num_runs, *args)
+ prof.print_stats(sort=options.profile_sort)
+ else:
+ data = bench_func(num_runs, *args)
+ if options.take_geo_mean:
+ product = reduce(operator.mul, data, 1)
+ print math.pow(product, 1.0 / len(data))
+ else:
+ for x in data:
+ print x
+
+
+def add_standard_options_to(parser):
+ """Add a bunch of common command-line flags to an existing OptionParser.
+
+ This function operates on `parser` in-place.
+
+ Args:
+ parser: optparse.OptionParser instance.
+ """
+ parser.add_option("-n", action="store", type="int", default=100,
+ dest="num_runs", help="Number of times to run the test.")
+ parser.add_option("--profile", action="store_true",
+ help="Run the benchmark through cProfile.")
+ parser.add_option("--profile_sort", action="store", type="str",
+ default="time", help="Column to sort cProfile output by.")
+ parser.add_option("--take_geo_mean", action="store_true",
+ help="Return the geo mean, rather than individual data.")
diff --git a/lib/Chameleon-2.9.2/distribute_setup.py b/lib/Chameleon-2.9.2/distribute_setup.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/distribute_setup.py
@@ -0,0 +1,485 @@
+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from distribute_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+ from site import USER_SITE
+except ImportError:
+ USER_SITE = None
+
+try:
+ import subprocess
+
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ return subprocess.call(args) == 0
+
+except ImportError:
+ # will be used for python 2.3
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ # quoting arguments if windows
+ if sys.platform == 'win32':
+ def quote(arg):
+ if ' ' in arg:
+ return '"%s"' % arg
+ return arg
+ args = [quote(arg) for arg in args]
+ return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.14"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # installing
+ log.warn('Installing Distribute')
+ if not _python_cmd('setup.py', 'install'):
+ log.warn('Something went wrong during the installation.')
+ log.warn('See the error message above.')
+ finally:
+ os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # building an egg
+ log.warn('Building a Distribute egg in %s', to_dir)
+ _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+ finally:
+ os.chdir(old_wd)
+ # returning the result
+ log.warn(egg)
+ if not os.path.exists(egg):
+ raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+ egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+ % (version, sys.version_info[0], sys.version_info[1]))
+ if not os.path.exists(egg):
+ tarball = download_setuptools(version, download_base,
+ to_dir, download_delay)
+ _build_egg(egg, tarball, to_dir)
+ sys.path.insert(0, egg)
+ import setuptools
+ setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, download_delay=15, no_fake=True):
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ was_imported = 'pkg_resources' in sys.modules or \
+ 'setuptools' in sys.modules
+ try:
+ try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ if not no_fake:
+ _fake_setuptools()
+ raise ImportError
+ except ImportError:
+ return _do_download(version, download_base, to_dir, download_delay)
+ try:
+ pkg_resources.require("distribute>="+version)
+ return
+ except pkg_resources.VersionConflict:
+ e = sys.exc_info()[1]
+ if was_imported:
+ sys.stderr.write(
+ "The required version of distribute (>=%s) is not available,\n"
+ "and can't be installed while this script is running. Please\n"
+ "install a more recent version first, using\n"
+ "'easy_install -U distribute'."
+ "\n\n(Currently using %r)\n" % (version, e.args[0]))
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ except pkg_resources.DistributionNotFound:
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ finally:
+ if not no_fake:
+ _create_fake_setuptools_pkg_info(to_dir)
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, delay=15):
+ """Download distribute from a specified location and return its filename
+
+ `version` should be a valid distribute version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download
+ attempt.
+ """
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+ tgz_name = "distribute-%s.tar.gz" % version
+ url = download_base + tgz_name
+ saveto = os.path.join(to_dir, tgz_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ log.warn("Downloading %s", url)
+ src = urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = src.read()
+ dst = open(saveto, "wb")
+ dst.write(data)
+ finally:
+ if src:
+ src.close()
+ if dst:
+ dst.close()
+ return os.path.realpath(saveto)
+
+def _no_sandbox(function):
+ def __no_sandbox(*args, **kw):
+ try:
+ from setuptools.sandbox import DirectorySandbox
+ if not hasattr(DirectorySandbox, '_old'):
+ def violation(*args):
+ pass
+ DirectorySandbox._old = DirectorySandbox._violation
+ DirectorySandbox._violation = violation
+ patched = True
+ else:
+ patched = False
+ except ImportError:
+ patched = False
+
+ try:
+ return function(*args, **kw)
+ finally:
+ if patched:
+ DirectorySandbox._violation = DirectorySandbox._old
+ del DirectorySandbox._old
+
+ return __no_sandbox
+
+def _patch_file(path, content):
+ """Will backup the file then patch it"""
+ existing_content = open(path).read()
+ if existing_content == content:
+ # already patched
+ log.warn('Already patched.')
+ return False
+ log.warn('Patching...')
+ _rename_path(path)
+ f = open(path, 'w')
+ try:
+ f.write(content)
+ finally:
+ f.close()
+ return True
+
+_patch_file = _no_sandbox(_patch_file)
+
+def _same_content(path, content):
+ return open(path).read() == content
+
+def _rename_path(path):
+ new_name = path + '.OLD.%s' % time.time()
+ log.warn('Renaming %s into %s', path, new_name)
+ os.rename(path, new_name)
+ return new_name
+
+def _remove_flat_installation(placeholder):
+ if not os.path.isdir(placeholder):
+ log.warn('Unkown installation at %s', placeholder)
+ return False
+ found = False
+ for file in os.listdir(placeholder):
+ if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+ found = True
+ break
+ if not found:
+ log.warn('Could not locate setuptools*.egg-info')
+ return
+
+ log.warn('Removing elements out of the way...')
+ pkg_info = os.path.join(placeholder, file)
+ if os.path.isdir(pkg_info):
+ patched = _patch_egg_dir(pkg_info)
+ else:
+ patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+ if not patched:
+ log.warn('%s already patched.', pkg_info)
+ return False
+ # now let's move the files out of the way
+ for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+ element = os.path.join(placeholder, element)
+ if os.path.exists(element):
+ _rename_path(element)
+ else:
+ log.warn('Could not find the %s element of the '
+ 'Setuptools distribution', element)
+ return True
+
+_remove_flat_installation = _no_sandbox(_remove_flat_installation)
+
+def _after_install(dist):
+ log.warn('After install bootstrap.')
+ placeholder = dist.get_command_obj('install').install_purelib
+ _create_fake_setuptools_pkg_info(placeholder)
+
+def _create_fake_setuptools_pkg_info(placeholder):
+ if not placeholder or not os.path.exists(placeholder):
+ log.warn('Could not find the install location')
+ return
+ pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+ setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+ (SETUPTOOLS_FAKED_VERSION, pyver)
+ pkg_info = os.path.join(placeholder, setuptools_file)
+ if os.path.exists(pkg_info):
+ log.warn('%s already exists', pkg_info)
+ return
+
+ log.warn('Creating %s', pkg_info)
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+
+ pth_file = os.path.join(placeholder, 'setuptools.pth')
+ log.warn('Creating %s', pth_file)
+ f = open(pth_file, 'w')
+ try:
+ f.write(os.path.join(os.curdir, setuptools_file))
+ finally:
+ f.close()
+
+_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
+
+def _patch_egg_dir(path):
+ # let's check if it's already patched
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ if os.path.exists(pkg_info):
+ if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+ log.warn('%s already patched.', pkg_info)
+ return False
+ _rename_path(path)
+ os.mkdir(path)
+ os.mkdir(os.path.join(path, 'EGG-INFO'))
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+ return True
+
+_patch_egg_dir = _no_sandbox(_patch_egg_dir)
+
+def _before_install():
+ log.warn('Before install bootstrap.')
+ _fake_setuptools()
+
+
+def _under_prefix(location):
+ if 'install' not in sys.argv:
+ return True
+ args = sys.argv[sys.argv.index('install')+1:]
+ for index, arg in enumerate(args):
+ for option in ('--root', '--prefix'):
+ if arg.startswith('%s=' % option):
+ top_dir = arg.split('root=')[-1]
+ return location.startswith(top_dir)
+ elif arg == option:
+ if len(args) > index:
+ top_dir = args[index+1]
+ return location.startswith(top_dir)
+ if arg == '--user' and USER_SITE is not None:
+ return location.startswith(USER_SITE)
+ return True
+
+
+def _fake_setuptools():
+ log.warn('Scanning installed packages')
+ try:
+ import pkg_resources
+ except ImportError:
+ # we're cool
+ log.warn('Setuptools or Distribute does not seem to be installed.')
+ return
+ ws = pkg_resources.working_set
+ try:
+ setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
+ replacement=False))
+ except TypeError:
+ # old distribute API
+ setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
+
+ if setuptools_dist is None:
+ log.warn('No setuptools distribution found')
+ return
+ # detecting if it was already faked
+ setuptools_location = setuptools_dist.location
+ log.warn('Setuptools installation detected at %s', setuptools_location)
+
+ # if --root or --preix was provided, and if
+ # setuptools is not located in them, we don't patch it
+ if not _under_prefix(setuptools_location):
+ log.warn('Not patching, --root or --prefix is installing Distribute'
+ ' in another location')
+ return
+
+ # let's see if its an egg
+ if not setuptools_location.endswith('.egg'):
+ log.warn('Non-egg installation')
+ res = _remove_flat_installation(setuptools_location)
+ if not res:
+ return
+ else:
+ log.warn('Egg installation')
+ pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+ if (os.path.exists(pkg_info) and
+ _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+ log.warn('Already patched.')
+ return
+ log.warn('Patching...')
+ # let's create a fake egg replacing setuptools one
+ res = _patch_egg_dir(setuptools_location)
+ if not res:
+ return
+ log.warn('Patched done.')
+ _relaunch()
+
+
+def _relaunch():
+ log.warn('Relaunching...')
+ # we have to relaunch the process
+ # pip marker to avoid a relaunch bug
+ if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
+ sys.argv[0] = 'setup.py'
+ args = [sys.executable] + sys.argv
+ sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+ """Extract all members from the archive to the current working
+ directory and set owner, modification time and permissions on
+ directories afterwards. `path' specifies a different directory
+ to extract to. `members' is optional and must be a subset of the
+ list returned by getmembers().
+ """
+ import copy
+ import operator
+ from tarfile import ExtractError
+ directories = []
+
+ if members is None:
+ members = self
+
+ for tarinfo in members:
+ if tarinfo.isdir():
+ # Extract directories with a safe mode.
+ directories.append(tarinfo)
+ tarinfo = copy.copy(tarinfo)
+ tarinfo.mode = 448 # decimal for oct 0700
+ self.extract(tarinfo, path)
+
+ # Reverse sort directories.
+ if sys.version_info < (2, 4):
+ def sorter(dir1, dir2):
+ return cmp(dir1.name, dir2.name)
+ directories.sort(sorter)
+ directories.reverse()
+ else:
+ directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+ # Set correct owner, mtime and filemode on directories.
+ for tarinfo in directories:
+ dirpath = os.path.join(path, tarinfo.name)
+ try:
+ self.chown(tarinfo, dirpath)
+ self.utime(tarinfo, dirpath)
+ self.chmod(tarinfo, dirpath)
+ except ExtractError:
+ e = sys.exc_info()[1]
+ if self.errorlevel > 1:
+ raise
+ else:
+ self._dbg(1, "tarfile: %s" % e)
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ tarball = download_setuptools()
+ _install(tarball)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/lib/Chameleon-2.9.2/docs/conf.py b/lib/Chameleon-2.9.2/docs/conf.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/conf.py
@@ -0,0 +1,194 @@
+# -*- coding: utf-8 -*-
+#
+# Chameleon documentation build configuration file, created by
+# sphinx-quickstart on Sun Nov 1 16:08:00 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Chameleon'
+copyright = u'2008-2011 by Malthe Borch and the Repoze Community'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '2.8'
+# The full version, including alpha/beta/rc tags.
+release = '2.8.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "Chameleon %s documentation" % version
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bchameleonm,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'chameleondoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'chameleon.tex', u'Chameleon Documentation',
+ u'Malthe Borch et. al', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/lib/Chameleon-2.9.2/docs/configuration.rst b/lib/Chameleon-2.9.2/docs/configuration.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/configuration.rst
@@ -0,0 +1,43 @@
+Configuration
+=============
+
+Most settings can be provided as keyword-arguments to the template
+constructor classes.
+
+There are certain settings which are required at environment
+level. Acceptable values are ``"0"``, ``"1"``, or the literals
+``"true"`` or ``"false"`` (case-insensitive).
+
+General usage
+-------------
+
+The following settings are useful in general.
+
+``CHAMELEON_EAGER``
+ Parse and compile templates on instantiation.
+
+``CHAMELEON_CACHE``
+
+ When set to a file system path, the template compiler will write
+ its output to files in this directory and use it as a cache.
+
+ This not only enables you to see the compiler output, but also
+ speeds up startup.
+
+``CHAMELEON_RELOAD``
+ This setting controls the default value of the ``auto_reload``
+ parameter.
+
+Development
+-----------
+
+The following settings are mostly useful during development or
+debugging of the library itself.
+
+``CHAMELEON_DEBUG``
+
+ Enables a set of debugging settings which make it easier to
+ discover and research issues with the engine itself.
+
+ This implicitly enables auto-reload for any template.
+
diff --git a/lib/Chameleon-2.9.2/docs/index.rst b/lib/Chameleon-2.9.2/docs/index.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/index.rst
@@ -0,0 +1,217 @@
+Chameleon
+=========
+
+Chameleon is an HTML/XML template engine for `Python
+<http://www.python.org>`_.
+
+It's designed to generate the document output of a web application,
+typically HTML markup or XML.
+
+The language used is *page templates*, originally a `Zope
+<http://www.zope.org>`_ invention [1]_, but available here as a
+:ref:`standalone library <no-dependencies>` that you can use in any
+script or application running Python 2.5 and up (including 3.x and
+`pypy <http://pypy.org>`_). It comes with a set of :ref:`new features
+<new-features>`, too.
+
+The template engine compiles templates into Python byte-code and is optimized
+for speed. For a complex template language, the performance is
+:ref:`very good <fast>`.
+
+ *Found a bug?* Please report issues to the `issue tracker <http://github.com/malthe/chameleon/issues>`_.
+
+ *Need help?* Post to the Pylons `discussion list <http://groups.google.com/group/pylons-discuss/>`_ or join the ``#pyramid`` channel on `Freenode IRC <http://freenode.net/>`_.
+
+Getting the code
+----------------
+
+You can `download <http://pypi.python.org/pypi/Chameleon#downloads>`_ the
+package from the Python package index or install the latest release
+using setuptools or the newer `distribute
+<http://packages.python.org/distribute/>`_ (required for Python 3.x)::
+
+ $ easy_install Chameleon
+
+.. _no-dependencies:
+
+There are no required library dependencies on Python 2.7 and up
+[2]_. On 2.5 and 2.6, the `ordereddict
+<http://pypi.python.org/pypi/ordereddict>`_ and `unittest2
+<http://pypi.python.org/pypi/unittest2>`_ packages are set as
+dependencies.
+
+The project is hosted in a `GitHub repository
+<http://github.com/malthe/chameleon>`_. Code contributions are
+welcome. The easiest way is to use the `pull request
+<http://help.github.com/pull-requests/>`_ interface.
+
+
+Introduction
+------------
+
+The *page templates* language is used within your document structure
+as special element attributes and text markup. Using a set of simple
+language constructs, you control the document flow, element
+repetition, text replacement and translation.
+
+.. note:: If you've used page templates in a Zope environment previously, note that Chameleon uses Python as the default expression language (instead of *path* expressions).
+
+The basic language (known as the *template attribute language* or TAL)
+is simple enough to grasp from an example:
+
+.. code-block:: genshi
+
+ <html>
+ <body>
+ <h1>Hello, ${'world'}!</h1>
+ <table>
+ <tr tal:repeat="row 'apple', 'banana', 'pineapple'">
+ <td tal:repeat="col 'juice', 'muffin', 'pie'">
+ ${row.capitalize()} ${col}
+ </td>
+ </tr>
+ </table>
+ </body>
+ </html>
+
+The ``${...}`` notation is short-hand for text insertion [3]_. The
+Python-expression inside the braces is evaluated and the result
+included in the output. By default, the string is escaped before
+insertion. To avoid this, use the ``structure:`` prefix:
+
+.. code-block:: genshi
+
+ <div>${structure: ...}</div>
+
+Note that if the expression result is an object that implements an
+``__html__()`` method [4]_, this method will be called and the result
+treated as "structure". An example of such an object is the
+``Markup`` class that's included as a utility::
+
+ from chameleon.utils import Markup
+ username = "<tt>%s</tt>" % username
+
+The macro language (known as the *macro expansion language* or METAL)
+provides a means of filling in portions of a generic template.
+
+On the left, the macro template; on the right, a template that loads
+and uses the macro, filling in the "content" slot:
+
+.. code-block:: genshi
+
+ <html xmlns="http://www.w3.org/1999/xhtml"> <metal:main use-macro="load: main.pt">
+ <head> <p metal:fill-slot="content">${structure: document.body}<p/>
+ <title>Example — ${document.title}</title> </metal:main>
+ </head>
+ <body>
+ <h1>${document.title}</h1>
+
+ <div id="content">
+ <metal:content define-slot="content" />
+ </div>
+ </body>
+ </html>
+
+In the example, the expression type :ref:`load <load-expression>` is
+used to retrieve a template from the file system using a path relative
+to the calling template.
+
+The METAL system works with TAL such that you can for instance fill in
+a slot that appears in a ``tal:repeat`` loop, or refer to variables
+defined using ``tal:define``.
+
+The third language subset is the translation system (known as the
+*internationalization language* or I18N):
+
+.. code-block:: genshi
+
+ <html i18n:domain="example">
+
+ ...
+
+ <div i18n:translate="">
+ You have <span i18n:name="amount">${round(amount, 2)}</span> dollars in your account.
+ </div>
+
+ ...
+
+ </html>
+
+Each translation message is marked up using ``i18n:translate`` and
+values can be mapped using ``i18n:name``. Attributes are marked for
+translation using ``i18n:attributes``. The template engine generates
+`gettext <http://www.gnu.org/s/gettext/>`_ translation strings from
+the markup::
+
+ "You have ${amount} dollars in your account."
+
+If you use a web framework such as `Pyramid
+<https://docs.pylonsproject.org/docs/pyramid.html>`_, the translation
+system is set up automatically and will negotiate on a *target
+language* based on the HTTP request or other parameter. If not, then
+you need to configure this manually.
+
+Next steps
+----------
+
+This was just an introduction. There are a number of other basic
+statements that you need to know in order to use the language. This is
+all covered in the :ref:`language reference <language-reference>`.
+
+If you're already familiar with the page template language, you can
+skip ahead to the :ref:`getting started <getting-started-with-cpt>`
+section to learn how to use the template engine in your code.
+
+To learn about integration with your favorite web framework see the
+section on :ref:`framework integration <framework-integration>`.
+
+License
+-------
+
+This software is made available under a BSD-like license.
+
+
+Contents
+========
+
+.. toctree::
+ :maxdepth: 2
+
+ library.rst
+ reference.rst
+ integration.rst
+ configuration.rst
+
+Indices and Tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+Notes
+=====
+
+.. [1] The template language specifications and API for the Page
+ Templates engine are based on Zope Page Templates (see in
+ particular `zope.pagetemplate
+ <http://pypi.python.org/pypi/zope.pagetemplate>`_). However,
+ the Chameleon compiler and Page Templates engine is an entirely
+ new codebase, packaged as a standalone distribution. It does
+ not require a Zope software environment.
+
+.. [2] The translation system in Chameleon is pluggable and based on
+ `gettext <http://www.gnu.org/s/gettext/>`_.
+ There is built-in support for the `zope.i18n
+ <http://pypi.python.org/pypi/zope.i18n>`_ package. If this
+ package is installed, it will be used by default. The
+ `translationstring
+ <http://pypi.python.org/pypi/translationstring>`_ package
+ offers some of the same helper and utility classes, without the
+ Zope application interface.
+
+.. [3] This syntax was taken from `Genshi <http://genshi.edgewall.org/>`_.
+
+.. [4] See the `WebHelpers
+ <https://docs.pylonsproject.org/projects/webhelpers/dev/modules/html/__init__.html>`_
+ library which provide a simple wrapper around this method.
diff --git a/lib/Chameleon-2.9.2/docs/integration.rst b/lib/Chameleon-2.9.2/docs/integration.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/integration.rst
@@ -0,0 +1,41 @@
+.. _framework-integration:
+
+Integration
+===========
+
+Integration with Chameleon is available for a number of popular web
+frameworks. The framework will usually provide loading mechanisms and
+translation (internationalization) configuration.
+
+Pyramid
+-------
+
+Chameleon is the default template engine for the `Pyramid
+<http://pylonsproject.org/projects/pyramid/about>`_ framework. See the
+section on `Page Templates
+<http://docs.pylonsproject.org/projects/pyramid/1.1/narr/templates.html#chameleon-zpt-templates>`_ for a complete reference.
+
+Zope 2 / Plone
+--------------
+
+Install the `five.pt <http://pypi.python.org/pypi/five.pt>`_ package
+to replace the reference template engine (globally).
+
+Zope Toolkit (ZTK)
+------------------
+
+Install the `z3c.pt <http://pypi.python.org/pypi/z3c.pt>`_ package for
+applications based on the `Zope Toolkit
+<http://docs.zope.org/zopetoolkit/>`_ (ZTK). Note that you need to
+explicit use the template classes from this package.
+
+Grok
+----
+
+Support for the `Grok <http://grok.zope.org/>`_ framework is available
+in the `grokcore.chameleon
+<http://pypi.python.org/pypi/grokcore.chameleon>`_ package.
+
+This package will setup Grok's policy for templating integration and
+associate the Chameleon template components for the ``.cpt`` template
+filename extension.
diff --git a/lib/Chameleon-2.9.2/docs/library.rst b/lib/Chameleon-2.9.2/docs/library.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/library.rst
@@ -0,0 +1,238 @@
+Library Documentation
+=====================
+
+This section documents the package as a Python library. To learn about
+the page template language, consult the :ref:`language reference
+<language-reference>`.
+
+.. _getting-started-with-cpt:
+
+Getting started
+---------------
+
+There are several template constructor classes available, one for each
+of the combinations *text* or *xml*, and *string* or *file*.
+
+The file-based constructor requires an absolute path. To set up a
+templates directory *once*, use the template loader class::
+
+ import os
+
+ path = os.path.dirname(__file__)
+
+ from chameleon import PageTemplateLoader
+ templates = PageTemplateLoader(os.path.join(path, "templates"))
+
+Then, to load a template relative to the provided path, use dictionary
+syntax::
+
+ template = templates['hello.pt']
+
+Alternatively, use the appropriate template class directly. Let's try
+with a string input::
+
+ from chameleon import PageTemplate
+ template = PageTemplate("<div>Hello, ${name}.</div>")
+
+All template instances are callable. Provide variables by keyword
+argument::
+
+ >>> template(name='John')
+ '<div>Hello, John.</div>'
+
+.. _fast:
+
+Performance
+-----------
+
+The template engine compiles (or *translates*) template source code
+into Python byte-code. In simple templates this yields an increase in
+performance of about 7 times in comparison to the reference
+implementation.
+
+In benchmarks for the content management system `Plone
+<http://www.plone.org>`_, switching to Chameleon yields a request to
+response improvement of 20-50%.
+
+Extension
+---------
+
+You can extend the language through the expression engine by writing
+your own expression compiler.
+
+Let's try and write an expression compiler for an expression type that
+will simply uppercase the supplied value. We'll call it ``upper``.
+
+You can write such a compiler as a closure:
+
+.. code-block:: python
+
+ import ast
+
+ def uppercase_expression(string):
+ def compiler(target, engine):
+ uppercased = self.string.uppercase()
+ value = ast.Str(uppercased)
+ return [ast.Assign(targets=[target], value=value)]
+ return compiler
+
+To make it available under a certain prefix, we'll add it to the
+expression types dictionary.
+
+.. code-block:: python
+
+ from chameleon import PageTemplate
+ PageTemplate.expression_types['upper'] = uppercase_expression
+
+Alternatively, you could subclass the template class and set the
+attribute ``expression_types`` to a dictionary that includes your
+expression:
+
+.. code-block:: python
+
+ from chameleon import PageTemplateFile
+ from chameleon.tales import PythonExpr
+
+ class MyPageTemplateFile(PageTemplateFile):
+ expression_types = {
+ 'python': PythonExpr,
+ 'upper': uppercase_expression
+ }
+
+You can now uppercase strings *natively* in your templates::
+
+ <div tal:content="upper: hello, world" />
+
+It's probably best to stick with a Python expression::
+
+ <div tal:content="'hello, world'.upper()" />
+
+
+.. _whats-new:
+
+Changes between 1.x and 2.x
+---------------------------
+
+This sections describes new features, improvements and changes from
+1.x to 2.x.
+
+New parser
+~~~~~~~~~~
+
+This series features a new, custom-built parser, implemented in pure
+Python. It parses both HTML and XML inputs (the previous parser relied
+on the expat system library and was more strict about its input).
+
+The main benefit of the new parser is that the compiler is now able to
+point to the source location of parse- and compilation errors much
+more accurately. This should be a great aid in debugging these errors.
+
+Compatible output
+~~~~~~~~~~~~~~~~~
+
+The 2.x engine matches the output of the reference implementation more
+closely (usually exactly). There are less differences altogether; for
+instance, the method of escaping TALES expression (usually a
+semicolon) has been changed to match that of the reference
+implementation.
+
+New language features
+~~~~~~~~~~~~~~~~~~~~~
+
+This series also introduces a number of new language features:
+
+1. Support for the ``tal:on-error`` from the reference specification
+ has been added.
+
+2. Two new attributes ``tal:switch`` and ``tal:case`` have been added
+ to make element conditions more flexible.
+
+
+Code improvements
+~~~~~~~~~~~~~~~~~
+
+The template classes have been refactored and simplified allowing
+better reuse of code and more intuitive APIs on the lower levels.
+
+Expression engine
+~~~~~~~~~~~~~~~~~
+
+The expression engine has been redesigned to make it easier to
+understand and extend. The new engine is based on the ``ast`` module
+(available since Python 2.6; backports included for Python 2.5). This
+means that expression compilers now need to return a valid list of AST
+statements that include an assignment to the target node.
+
+Compiler
+~~~~~~~~
+
+The new compiler has been optimized for complex templates. As a
+result, in the benchmark suite included with the package, this
+compiler scores about half of the 1.x series. For most real world
+applications, the engine should still perform as well as the 1.x
+series.
+
+
+API reference
+-------------
+
+This section describes the documented API of the library.
+
+Template classes
+~~~~~~~~~~~~~~~~
+
+Use the ``PageTemplate*`` template classes to define a template from a
+string or file input:
+
+.. automodule:: chameleon
+
+ .. autoclass:: chameleon.PageTemplate
+
+ Note: The remaining classes take the same general configuration
+ arguments.
+
+ .. automethod:: render
+
+ .. autoclass:: chameleon.PageTemplateFile(filename, **config)
+
+ .. autoclass:: chameleon.PageTextTemplate
+
+ .. autoclass:: chameleon.PageTextTemplateFile
+
+Template loader
+~~~~~~~~~~~~~~~
+
+Some systems have framework support for loading templates from
+files. The following loader class is directly compatible with the
+Pylons framework and may be adapted to other frameworks:
+
+.. class:: chameleon.PageTemplateLoader(search_path=None, default_extension=None, **config)
+
+ Load templates from ``search_path`` (must be a string or a list of
+ strings)::
+
+ templates = PageTemplateLoader(path)
+ example = templates['example.pt']
+
+ If ``default_extension`` is provided, this will be added to inputs
+ that do not already have an extension::
+
+ templates = PageTemplateLoader(path, ".pt")
+ example = templates['example']
+
+ Any additional keyword arguments will be passed to the template
+ constructor::
+
+ templates = PageTemplateLoader(path, debug=True, encoding="utf-8")
+
+ .. automethod:: load
+
+Expression engine
+~~~~~~~~~~~~~~~~~
+
+For advanced integration, the compiler module provides support for
+dynamic expression evaluation:
+
+.. automodule:: chameleon.compiler
+
+ .. autoclass:: chameleon.compiler.ExpressionEvaluator
diff --git a/lib/Chameleon-2.9.2/docs/reference.rst b/lib/Chameleon-2.9.2/docs/reference.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/reference.rst
@@ -0,0 +1,1695 @@
+:tocdepth: 4
+
+.. _language-reference:
+
+.. highlight:: xml
+
+Language Reference
+==================
+
+The language reference is structured such that it can be read as a
+general introduction to the *page templates* language.
+
+It's split into parts that correspond to each of the main language
+features.
+
+Syntax
+######
+
+You can safely :ref:`skip this section <tal>` if you're familiar with
+how template languages work or just want to learn by example.
+
+An *attribute language* is a programming language designed to render
+documents written in XML or HTML markup. The input must be a
+well-formed document. The output from the template is usually
+XML-like but isn't required to be well-formed.
+
+The statements of the language are document tags with special
+attributes, and look like this::
+
+ <p namespace-prefix:command="argument"> ... </p>
+
+In the above example, the attribute
+``namespace-prefix:command="argument"`` is the statement, and the
+entire paragraph tag is the statement's element. The statement's
+element is the portion of the document on which this statement
+operates.
+
+The namespace prefixes are typically declared once, at the top of a
+template (note that prefix declarations for the template language
+namespaces are omitted from the template output)::
+
+ <html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ ...
+ </html>
+
+Thankfully, sane namespace prefix defaults are in place to let us skip
+most of the boilerplate::
+
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <p tal:content="text"> ... </p>
+ </body>
+ </html>
+
+Note how ``tal`` is used without an explicit namespace
+declaration. Chameleon sets up defaults for ``metal`` and ``i18n`` as
+well.
+
+.. note:: Default prefixes are a special feature of Chameleon.
+
+.. _tal:
+
+Basics (TAL)
+############
+
+The *template attribute language* is used to create dynamic XML-like
+content. It allows elements of a document to be replaced, repeated,
+or omitted.
+
+Statements
+----------
+
+These are the available statements:
+
+================== ==============
+ Statement Description
+================== ==============
+``tal:define`` Define variables.
+``tal:switch`` Defines a switch condition
+``tal:condition`` Include element only if expression is true.
+``tal:repeat`` Repeat an element.
+``tal:case`` Includes element only if expression is equal to parent switch.
+``tal:content`` Substitute the content of an element.
+``tal:replace`` Replace the element with dynamic content.
+``tal:omit-tag`` Omit the element tags, leaving only the inner content.
+``tal:attributes`` Dynamically change or insert element attributes.
+``tal:on-error`` Substitute the content of an element if processing fails.
+================== ==============
+
+When there is only one TAL statement per element, the order in which
+they are executed is simple. Starting with the root element, each
+element's statements are executed, then each of its child elements is
+visited, in order, to do the same::
+
+ <html>
+ <meta>
+ <title tal:content="context.title" />
+ </meta>
+ <body>
+ <div tal:condition="items">
+ <p>These are your items:</p>
+ <ul>
+ <li tal:repeat="item items" tal:content="item" />
+ </ul>
+ </div>
+ </body>
+ </html>
+
+Any combination of statements may appear on the same element, except
+that the ``tal:content`` and ``tal:replace`` statements may not be
+used on the same element.
+
+.. note:: The ``tal:case`` and ``tal:switch`` statements are available
+ in Chameleon only.
+
+TAL does not use use the order in which statements are written in the
+tag to determine the order in which they are executed. When an
+element has multiple statements, they are executed in the order
+printed in the table above.
+
+There is a reasoning behind this ordering. Because users often want
+to set up variables for use in other statements contained within this
+element or subelements, ``tal:define`` is executed first. Then any
+switch statement. ``tal:condition`` follows, then ``tal:repeat``, then
+``tal:case``. We are now rendering an element; first ``tal:content``
+or ``tal:replace``. Finally, before ``tal:attributes``, we have
+``tal:omit-tag`` (which is implied with ``tal:replace``).
+
+.. note:: *TALES* is used as the expression language for the "stuff in
+ the quotes". The default syntax is simply Python, but
+ other inputs are possible --- see the section on :ref:`expressions
+ <tales>`.
+
+``tal:attributes``
+^^^^^^^^^^^^^^^^^^
+
+Updates or inserts element attributes.
+
+::
+
+ tal:attributes="href request.url"
+
+Syntax
+~~~~~~
+
+``tal:attributes`` syntax::
+
+ argument ::= attribute_statement [';' attribute_statement]*
+ attribute_statement ::= attribute_name expression
+ attribute_name ::= [namespace-prefix ':'] Name
+ namespace-prefix ::= Name
+
+
+Description
+~~~~~~~~~~~
+
+The ``tal:attributes`` statement replaces the value of an attribute
+(or creates an attribute) with a dynamic value. The
+value of each expression is converted to a string, if necessary.
+
+.. note:: You can qualify an attribute name with a namespace prefix,
+ for example ``html:table``, if you are generating an XML document
+ with multiple namespaces.
+
+If an attribute expression evaluates to ``None``, the attribute is
+deleted from the statement element (or simply not inserted).
+
+If the expression evaluates to the symbol ``default`` (a symbol which
+is always available when evaluating attributes), its value is defined
+as the default static attribute value. If there is no such default
+value, a return value of ``default`` will drop the attribute.
+
+If you use ``tal:attributes`` on an element with an active
+``tal:replace`` command, the ``tal:attributes`` statement is ignored.
+
+If you use ``tal:attributes`` on an element with a ``tal:repeat``
+statement, the replacement is made on each repetition of the element,
+and the replacement expression is evaluated fresh for each repetition.
+
+.. note:: If you want to include a semicolon (";") in an expression, it
+ must be escaped by doubling it (";;") [1]_.
+
+Examples
+~~~~~~~~
+
+Replacing a link::
+
+ <a href="/sample/link.html"
+ tal:attributes="href context.url()"
+ >
+ ...
+ </a>
+
+Replacing two attributes::
+
+ <textarea rows="80" cols="20"
+ tal:attributes="rows request.rows();cols request.cols()"
+ />
+
+A checkbox input::
+
+ <input type="input" tal:attributes="checked True" />
+
+``tal:condition``
+^^^^^^^^^^^^^^^^^
+
+Conditionally includes or omits an element::
+
+ <div tal:condition="comments">
+ ...
+ </div>
+
+Syntax
+~~~~~~
+
+``tal:condition`` syntax::
+
+ argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+ The ``tal:condition`` statement includes the statement element in the
+ template only if the condition is met, and omits it otherwise. If
+ its expression evaluates to a *true* value, then normal processing of
+ the element continues, otherwise the statement element is immediately
+ removed from the template. For these purposes, the value ``nothing``
+ is false, and ``default`` has the same effect as returning a true
+ value.
+
+.. note:: Like Python itself, ZPT considers None, zero, empty strings,
+ empty sequences, empty dictionaries, and instances which return a
+ nonzero value from ``__len__`` or ``__nonzero__`` false; all other
+ values are true, including ``default``.
+
+Examples
+~~~~~~~~
+
+Test a variable before inserting it::
+
+ <p tal:condition="request.message" tal:content="request.message" />
+
+Testing for odd/even in a repeat-loop::
+
+ <div tal:repeat="item range(10)">
+ <p tal:condition="repeat.item.even">Even</p>
+ <p tal:condition="repeat.item.odd">Odd</p>
+ </div>
+
+``tal:content``
+^^^^^^^^^^^^^^^
+
+Replaces the content of an element.
+
+Syntax
+~~~~~~
+
+``tal:content`` syntax::
+
+ argument ::= (['text'] | 'structure') expression
+
+Description
+~~~~~~~~~~~
+
+Rather than replacing an entire element, you can insert text or
+structure in place of its children with the ``tal:content`` statement.
+The statement argument is exactly like that of ``tal:replace``, and is
+interpreted in the same fashion. If the expression evaluates to
+``nothing``, the statement element is left childless. If the
+expression evaluates to ``default``, then the element's contents are
+evaluated.
+
+The default replacement behavior is ``text``, which replaces
+angle-brackets and ampersands with their HTML entity equivalents. The
+``structure`` keyword passes the replacement text through unchanged,
+allowing HTML/XML markup to be inserted. This can break your page if
+the text contains unanticipated markup (eg. text submitted via a web
+form), which is the reason that it is not the default.
+
+.. note:: The ``structure`` keyword exists to provide backwards
+ compatibility. In Chameleon, the ``structure:`` expression
+ type provides the same functionality (also for inline
+ expressions).
+
+
+Examples
+~~~~~~~~
+
+Inserting the user name::
+
+ <p tal:content="user.getUserName()">Fred Farkas</p>
+
+Inserting HTML/XML::
+
+ <p tal:content="structure context.getStory()">
+ Marked <b>up</b> content goes here.
+ </p>
+
+``tal:define``
+^^^^^^^^^^^^^^
+
+Defines local variables.
+
+Syntax
+~~~~~~
+
+``tal:define`` syntax::
+
+ argument ::= define_scope [';' define_scope]*
+ define_scope ::= (['local'] | 'global')
+ define_var define_var ::= variable_name
+ expression variable_name ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``tal:define`` statement defines variables. When you define a
+local variable in a statement element, you can use that variable in
+that element and the elements it contains. If you redefine a variable
+in a contained element, the new definition hides the outer element's
+definition within the inner element.
+
+Note that valid variable names are any Python identifier string
+including underscore, although two or more leading underscores are
+disallowed (used internally by the compiler). Further, names are
+case-sensitive.
+
+Python builtins are always "in scope", but most of them may be
+redefined (such as ``help``). Exceptions are:: ``float``, ``int``,
+``len``, ``long``, ``str``, ``None``, ``True`` and ``False``.
+
+In addition, the following names are reserved: ``econtext``,
+``rcontext``, ``translate``, ``decode`` and ``convert``.
+
+If the expression associated with a variable evaluates to ``nothing``,
+then that variable has the value ``nothing``, and may be used as such
+in further expressions. Likewise, if the expression evaluates to
+``default``, then the variable has the value ``default``, and may be
+used as such in further expressions.
+
+You can define two different kinds of variables: *local* and
+*global*. When you define a local variable in a statement element, you
+can only use that variable in that element and the elements it
+contains. If you redefine a local variable in a contained element, the
+new definition hides the outer element's definition within the inner
+element. When you define a global variables, you can use it in any
+element processed after the defining element. If you redefine a global
+variable, you replace its definition for the rest of the template.
+
+To set the definition scope of a variable, use the keywords ``local``
+or ``global`` in front of the assignment. The default setting is
+``local``; thus, in practice, only the ``global`` keyword is used.
+
+.. note:: If you want to include a semicolon (";") in an expression, it
+ must be escaped by doubling it (";;") [1]_.
+
+Examples
+~~~~~~~~
+
+Defining a variable::
+
+ tal:define="company_name 'Zope Corp, Inc.'"
+
+Defining two variables, where the second depends on the first::
+
+ tal:define="mytitle context.title; tlen len(mytitle)"
+
+
+``tal:switch`` and ``tal:case``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Defines a switch clause.
+
+::
+
+ <ul tal:switch="len(items) % 2">
+ <li tal:case="True">odd</li>
+ <li tal:case="False">even</li>
+ </ul>
+
+Syntax
+~~~~~~
+
+``tal:case`` and ``tal:switch`` syntax::
+
+ argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+The *switch* and *case* construct is a short-hand syntax for
+evaluating a set of expressions against a parent value.
+
+The ``tal:switch`` statement is used to set a new parent value and the
+``tal:case`` statement works like a condition and only allows content
+if the expression matches the value.
+
+Note that if the case expression is the symbol ``default``, it always
+matches the switch.
+
+.. note:: These statements are only available in Chameleon 2.x and not
+ part of the ZPT specification.
+
+Examples
+~~~~~~~~
+
+::
+
+ <ul tal:switch="item.type">
+ <li tal:case="'document'">
+ Document
+ </li>
+ <li tal:case="'folder'">
+ Folder
+ </li>
+ </ul>
+
+Note that any and all cases that match the switch will be included.
+
+
+``tal:omit-tag``
+^^^^^^^^^^^^^^^^
+
+Removes an element, leaving its contents.
+
+Syntax
+~~~~~~
+
+``tal:omit-tag`` syntax::
+
+ argument ::= [ expression ]
+
+Description
+~~~~~~~~~~~
+
+The ``tal:omit-tag`` statement leaves the contents of an element in
+place while omitting the surrounding start and end tags.
+
+If the expression evaluates to a *false* value, then normal processing
+of the element continues and the tags are not omitted. If the
+expression evaluates to a *true* value, or no expression is provided,
+the statement element is replaced with its contents.
+
+.. note:: Like Python itself, ZPT considers None, zero, empty strings,
+ empty sequences, empty dictionaries, and instances which return a
+ nonzero value from ``__len__`` or ``__nonzero__`` false; all other
+ values are true, including ``default``.
+
+Examples
+~~~~~~~~
+
+Unconditionally omitting a tag::
+
+ <div tal:omit-tag="" comment="This tag will be removed">
+ <i>...but this text will remain.</i>
+ </div>
+
+Conditionally omitting a tag::
+
+ <b tal:omit-tag="not:bold">I may be bold.</b>
+
+The above example will omit the ``b`` tag if the variable ``bold`` is false.
+
+Creating ten paragraph tags, with no enclosing tag::
+
+ <span tal:repeat="n range(10)"
+ tal:omit-tag="">
+ <p tal:content="n">1</p>
+ </span>
+
+.. _tal_repeat:
+
+``tal:repeat``
+^^^^^^^^^^^^^^
+
+Repeats an element.
+
+Syntax
+~~~~~~
+
+``tal:repeat`` syntax::
+
+ argument ::= variable_name expression
+ variable_name ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``tal:repeat`` statement replicates a sub-tree of your document
+once for each item in a sequence. The expression should evaluate to a
+sequence. If the sequence is empty, then the statement element is
+deleted, otherwise it is repeated for each value in the sequence. If
+the expression is ``default``, then the element is left unchanged, and
+no new variables are defined.
+
+The ``variable_name`` is used to define a local variable and a repeat
+variable. For each repetition, the local variable is set to the
+current sequence element, and the repeat variable is set to an
+iteration object.
+
+Repeat variables
+~~~~~~~~~~~~~~~~~
+
+You use repeat variables to access information about the current
+repetition (such as the repeat index). The repeat variable has the
+same name as the local variable, but is only accessible through the
+built-in variable named ``repeat``.
+
+The following information is available from the repeat variable:
+
+================== ==============
+ Attribute Description
+================== ==============
+``index`` Repetition number, starting from zero.
+``number`` Repetition number, starting from one.
+``even`` True for even-indexed repetitions (0, 2, 4, ...).
+``odd`` True for odd-indexed repetitions (1, 3, 5, ...).
+``start`` True for the starting repetition (index 0).
+``end`` True for the ending, or final, repetition.
+``first`` True for the first item in a group - see note below
+``last`` True for the last item in a group - see note below
+``length`` Length of the sequence, which will be the total number of repetitions.
+``letter`` Repetition number as a lower-case letter: "a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and so forth.
+``Letter`` Upper-case version of *letter*.
+``roman`` Repetition number as a lower-case roman numeral: "i", "ii", "iii", "iv", "v", etc.
+``Roman`` Upper-case version of *roman*.
+================== ==============
+
+You can access the contents of the repeat variable using either
+dictionary- or attribute-style access, e.g. ``repeat['item'].start``
+or ``repeat.item.start``.
+
+.. note:: For legacy compatibility, the attributes ``odd``, ``even``, ``number``, ``letter``, ``Letter``, ``roman``, and ``Roman`` are callable (returning ``self``).
+
+Note that ``first`` and ``last`` are intended for use with sorted
+sequences. They try to divide the sequence into group of items with
+the same value.
+
+Examples
+~~~~~~~~
+
+Iterating over a sequence of strings::
+
+ <p tal:repeat="txt ('one', 'two', 'three')">
+ <span tal:replace="txt" />
+ </p>
+
+Inserting a sequence of table rows, and using the repeat variable
+to number the rows::
+
+ <table>
+ <tr tal:repeat="item here.cart">
+ <td tal:content="repeat.item.number">1</td>
+ <td tal:content="item.description">Widget</td>
+ <td tal:content="item.price">$1.50</td>
+ </tr>
+ </table>
+
+Nested repeats::
+
+ <table border="1">
+ <tr tal:repeat="row range(10)">
+ <td tal:repeat="column range(10)">
+ <span tal:define="x repeat.row.number;
+ y repeat.column.number;
+ z x * y"
+ tal:replace="string:$x * $y = $z">1 * 1 = 1</span>
+ </td>
+ </tr>
+ </table>
+
+Insert objects. Separates groups of objects by type by drawing a rule
+between them::
+
+ <div tal:repeat="object objects">
+ <h2 tal:condition="repeat.object.first.meta_type"
+ tal:content="object.type">Meta Type</h2>
+ <p tal:content="object.id">Object ID</p>
+ <hr tal:condition="object.last.meta_type" />
+ </div>
+
+.. note:: the objects in the above example should already be sorted by
+ type.
+
+``tal:replace``
+^^^^^^^^^^^^^^^
+
+Replaces an element.
+
+Syntax
+~~~~~~
+
+``tal:replace`` syntax::
+
+ argument ::= ['structure'] expression
+
+Description
+~~~~~~~~~~~
+
+
+The ``tal:replace`` statement replaces an element with dynamic
+content. It replaces the statement element with either text or a
+structure (unescaped markup). The body of the statement is an
+expression with an optional type prefix. The value of the expression
+is converted into an escaped string unless you provide the 'structure' prefix. Escaping consists of converting ``&`` to
+``&``, ``<`` to ``<``, and ``>`` to ``>``.
+
+.. note:: If the inserted object provides an ``__html__`` method, that method is called with the result inserted as structure. This feature is not implemented by ZPT.
+
+If the expression evaluates to ``None``, the element is simply removed. If the value is ``default``, then the element is left unchanged.
+
+Examples
+~~~~~~~~
+
+Inserting a title::
+
+ <span tal:replace="context.title">Title</span>
+
+Inserting HTML/XML::
+
+ <div tal:replace="structure table" />
+
+.. _tales:
+
+Expressions (TALES)
+###################
+
+The *Template Attribute Language Expression Syntax* (TALES) standard
+describes expressions that supply :ref:`tal` and
+:ref:`metal` with data. TALES is *one* possible expression
+syntax for these languages, but they are not bound to this definition.
+Similarly, TALES could be used in a context having nothing to do with
+TAL or METAL.
+
+TALES expressions are described below with any delimiter or quote
+markup from higher language layers removed. Here is the basic
+definition of TALES syntax::
+
+ Expression ::= [type_prefix ':'] String
+ type_prefix ::= Name
+
+Here are some simple examples::
+
+ 1 + 2
+ None
+ string:Hello, ${view.user_name}
+
+The optional *type prefix* determines the semantics and syntax of the
+*expression string* that follows it. A given implementation of TALES
+can define any number of expression types, with whatever syntax you
+like. It also determines which expression type is indicated by
+omitting the prefix.
+
+Types
+-----
+
+These are the available TALES expression types:
+
+============= ==============
+ Prefix Description
+============= ==============
+``exists`` Evaluate the result inside an exception handler; if one of the exceptions ``AttributeError``, ``LookupError``, ``TypeError``, ``NameError``, or ``KeyError`` is raised during evaluation, the result is ``False``, otherwise ``True``. Note that the original result is discarded in any case.
+``import`` Import a global symbol using dotted notation.
+``load`` Load a template relative to the current template or absolute.
+``not`` Negate the expression result
+``python`` Evaluate a Python expression
+``string`` Format a string
+``structure`` Wraps the expression result as *structure*.
+============= ==============
+
+.. note:: The default expression type is ``python``.
+
+.. warning:: The Zope reference engine defaults to a ``path``
+ expression type, which is closely tied to the Zope
+ framework. This expression is not implemented in
+ Chameleon (but it's available in a Zope framework
+ compatibility package).
+
+There's a mechanism to allow fallback to alternative expressions, if
+one should fail (raise an exception). The pipe character ('|') is used
+to separate two expressions::
+
+ <div tal:define="page request.GET['page'] | 0">
+
+This mechanism applies only to the ``python`` expression type, and by
+derivation ``string``.
+
+.. _tales_built_in_names:
+
+``python``
+^^^^^^^^^^
+
+Evaluates a Python expression.
+
+Syntax
+~~~~~~
+
+Python expression syntax::
+
+ Any valid Python language expression
+
+Description
+~~~~~~~~~~~
+
+Python expressions are executed natively within the translated
+template source code. There is no built-in security apparatus.
+
+``string``
+^^^^^^^^^^
+
+Syntax
+~~~~~~
+
+String expression syntax::
+
+ string_expression ::= ( plain_string | [ varsub ] )*
+ varsub ::= ( '$' Variable ) | ( '${ Expression }' )
+ plain_string ::= ( '$$' | non_dollar )*
+ non_dollar ::= any character except '$'
+
+Description
+~~~~~~~~~~~
+
+String expressions interpret the expression string as text. If no
+expression string is supplied the resulting string is *empty*. The
+string can contain variable substitutions of the form ``$name`` or
+``${expression}``, where ``name`` is a variable name, and ``expression`` is a TALES-expression. The escaped string value of the expression is inserted into the string.
+
+.. note:: To prevent a ``$`` from being interpreted this
+ way, it must be escaped as ``$$``.
+
+Examples
+~~~~~~~~
+
+Basic string formatting::
+
+ <span tal:replace="string:$this and $that">
+ Spam and Eggs
+ </span>
+
+ <p tal:content="string:${request.form['total']}">
+ total: 12
+ </p>
+
+Including a dollar sign::
+
+ <p tal:content="string:$$$cost">
+ cost: $42.00
+ </p>
+
+.. _import-expression:
+
+``import``
+^^^^^^^^^^
+
+Imports a module global.
+
+.. _structure-expression:
+
+``structure``
+^^^^^^^^^^^^^
+
+Wraps the expression result as *structure*: The replacement text is
+inserted into the document without escaping, allowing HTML/XML markup
+to be inserted. This can break your page if the text contains
+unanticipated markup (eg. text submitted via a web form), which is
+the reason that it is not the default.
+
+.. _load-expression:
+
+``load``
+^^^^^^^^
+
+Loads a template instance.
+
+Syntax
+~~~~~~
+
+Load expression syntax::
+
+ Relative or absolute file path
+
+Description
+~~~~~~~~~~~
+
+The template will be loaded using the same template class as the
+calling template.
+
+Examples
+~~~~~~~~
+
+Loading a template and using it as a macro::
+
+ <div tal:define="master load: ../master.pt" metal:use-macro="master" />
+
+
+Built-in names
+--------------
+
+These are the names always available in the TALES expression namespace:
+
+- ``default`` - special value used to specify that existing text or attributes should not be replaced. See the documentation for individual TAL statements for details on how they interpret *default*.
+
+- ``repeat`` - the *repeat* variables; see :ref:`tal_repeat` for more
+ information.
+
+- ``template`` - reference to the template which was first called; this symbol is carried over when using macros.
+
+- ``macros`` - reference to the macros dictionary that corresponds to the current template.
+
+
+.. _metal:
+
+Macros (METAL)
+##############
+
+The *Macro Expansion Template Attribute Language* (METAL) standard is
+a facility for HTML/XML macro preprocessing. It can be used in
+conjunction with or independently of TAL and TALES.
+
+Macros provide a way to define a chunk of presentation in one
+template, and share it in others, so that changes to the macro are
+immediately reflected in all of the places that share it.
+Additionally, macros are always fully expanded, even in a template's
+source text, so that the template appears very similar to its final
+rendering.
+
+A single Page Template can accomodate multiple macros.
+
+Namespace
+---------
+
+The METAL namespace URI and recommended alias are currently defined
+as::
+
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+
+Just like the TAL namespace URI, this URI is not attached to a web
+page; it's just a unique identifier. This identifier must be used in
+all templates which use METAL.
+
+Statements
+----------
+
+METAL defines a number of statements:
+
+* ``metal:define-macro`` Define a macro.
+* ``metal:use-macro`` Use a macro.
+* ``metal:extend-macro`` Extend a macro.
+* ``metal:define-slot`` Define a macro customization point.
+* ``metal:fill-slot`` Customize a macro.
+
+Although METAL does not define the syntax of expression non-terminals,
+leaving that up to the implementation, a canonical expression syntax
+for use in METAL arguments is described in TALES Specification.
+
+``define-macro``
+^^^^^^^^^^^^^^^^
+
+Defines a macro.
+
+Syntax
+~~~~~~
+
+``metal:define-macro`` syntax::
+
+ argument ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``metal:define-macro`` statement defines a macro. The macro is named
+by the statement expression, and is defined as the element and its
+sub-tree.
+
+Examples
+~~~~~~~~
+
+Simple macro definition::
+
+ <p metal:define-macro="copyright">
+ Copyright 2011, <em>Foobar</em> Inc.
+ </p>
+
+``define-slot``
+^^^^^^^^^^^^^^^
+
+Defines a macro customization point.
+
+Syntax
+~~~~~~
+
+``metal:define-slot`` syntax::
+
+ argument ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``metal:define-slot`` statement defines a macro customization
+point or *slot*. When a macro is used, its slots can be replaced, in
+order to customize the macro. Slot definitions provide default content
+for the slot. You will get the default slot contents if you decide not
+to customize the macro when using it.
+
+The ``metal:define-slot`` statement must be used inside a
+``metal:define-macro`` statement.
+
+Slot names must be unique within a macro.
+
+Examples
+~~~~~~~~
+
+Simple macro with slot::
+
+ <p metal:define-macro="hello">
+ Hello <b metal:define-slot="name">World</b>
+ </p>
+
+This example defines a macro with one slot named ``name``. When you use
+this macro you can customize the ``b`` element by filling the ``name``
+slot.
+
+``fill-slot``
+^^^^^^^^^^^^^
+
+Customize a macro.
+
+Syntax
+~~~~~~
+
+``metal:fill-slot`` syntax::
+
+ argument ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``metal:fill-slot`` statement customizes a macro by replacing a
+*slot* in the macro with the statement element (and its content).
+
+The ``metal:fill-slot`` statement must be used inside a
+``metal:use-macro`` statement.
+
+Slot names must be unique within a macro.
+
+If the named slot does not exist within the macro, the slot
+contents will be silently dropped.
+
+Examples
+~~~~~~~~
+
+Given this macro::
+
+ <p metal:define-macro="hello">
+ Hello <b metal:define-slot="name">World</b>
+ </p>
+
+You can fill the ``name`` slot like so::
+
+ <p metal:use-macro="container['master.html'].macros.hello">
+ Hello <b metal:fill-slot="name">Kevin Bacon</b>
+ </p>
+
+``use-macro``
+^^^^^^^^^^^^^
+
+Use a macro.
+
+Syntax
+~~~~~~
+
+``metal:use-macro`` syntax::
+
+ argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+The ``metal:use-macro`` statement replaces the statement element with
+a macro. The statement expression describes a macro definition.
+
+.. note:: In Chameleon the expression may point to a template instance; in this case it will be rendered in its entirety.
+
+``extend-macro``
+^^^^^^^^^^^^^^^^
+
+Extends a macro.
+
+Syntax
+~~~~~~
+
+``metal:extend-macro`` syntax::
+
+ argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+To extend an existing macro, choose a name for the macro and add a
+define-macro attribute to a document element with the name as the
+argument. Add an extend-macro attribute to the document element with
+an expression referencing the base macro as the argument. The
+extend-macro must be used in conjunction with define-macro, and must
+not be used with use-macro. The element's subtree is the macro
+body.
+
+Examples
+~~~~~~~~
+
+::
+
+ <div metal:define-macro="page-header"
+ metal:extend-macro="standard_macros['page-header']">
+ <div metal:fill-slot="breadcrumbs">
+ You are here:
+ <div metal:define-slot="breadcrumbs"/>
+ </div>
+ </div>
+
+
+.. _i18n:
+
+Translation (I18N)
+##################
+
+Translation of template contents and attributes is supported via the
+``i18n`` namespace and message objects.
+
+Messages
+--------
+
+The translation machinery defines a message as *any object* which is
+not a string or a number and which does not provide an ``__html__``
+method.
+
+When any such object is inserted into the template, the translate
+function is invoked first to see if it needs translation. The result
+is always coerced to a native string before it's inserted into the
+template.
+
+Translation function
+--------------------
+
+The simplest way to hook into the translation machinery is to provide
+a translation function to the template constructor or at
+render-time. In either case it should be passed as the keyword
+argument ``translate``.
+
+The function has the following signature:
+
+.. code-block:: python
+
+ def translate(msgid, domain=None, mapping=None, context=None, target_language=None, default=None):
+ ...
+
+The result should be a string or ``None``. If another type of object
+is returned, it's automatically coerced into a string.
+
+If `zope.i18n <http://pypi.python.org/pypi/zope.i18n>`_ is available,
+the translation machinery defaults to using its translation
+function. Note that this function requires messages to conform to the
+message class from `zope.i18nmessageid
+<http://pypi.python.org/pypi/zope.i18nmessageid>`_; specifically,
+messages must have attributes ``domain``, ``mapping`` and
+``default``. Example use:
+
+.. code-block:: python
+
+ from zope.i18nmessageid import MessageFactory
+ _ = MessageFactory("food")
+
+ apple = _(u"Apple")
+
+There's currently no further support for other translation frameworks.
+
+Using Zope's translation framework
+-----------------------------------
+
+The translation function from ``zope.i18n`` relies on *translation
+domains* to provide translations.
+
+These are components that are registered for some translation domain
+identifier and which implement a ``translate`` method that translates
+messages for that domain.
+
+.. note:: To register translation domain components, the Zope Component Architecture must be used (see `zope.component <http://pypi.python.org/pypi/zope.component>`_).
+
+The easiest way to configure translation domains is to use the the
+``registerTranslations`` ZCML-directive; this requires the use of the
+`zope.configuration <http://pypi.python.org/pypi/zope.configuration>`_
+package. This will set up translation domains and gettext catalogs
+automatically:
+
+.. code-block:: xml
+
+ <configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+
+ <i18n:registerTranslations directory="locales" />
+
+ </configure>
+
+The ``./locales`` directory must follow a particular directory
+structure:
+
+.. code-block:: bash
+
+ ./locales/en/LC_MESSAGES
+ ./locales/de/LC_MESSAGES
+ ...
+
+In each of the ``LC_MESSAGES`` directories, one `GNU gettext
+<http://en.wikipedia.org/wiki/GNU_gettext>`_ file in the ``.po``
+format must be present per translation domain:
+
+.. code-block:: po
+
+ # ./locales/de/LC_MESSAGES/food.po
+
+ msgid ""
+ msgstr ""
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+
+ msgid "Apple"
+ msgstr "Apfel"
+
+It may be necessary to compile the message catalog using the
+``msgfmt`` utility. This will produce a ``.mo`` file.
+
+Translation domains without gettext
+-----------------------------------
+
+The following example demonstrates how to manually set up and
+configure a translation domain for which messages are provided
+directly::
+
+ from zope import component
+ from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+
+ food = SimpleTranslationDomain("food", {
+ ('de', u'Apple'): u'Apfel',
+ })
+
+ component.provideUtility(food, food.domain)
+
+An example of a custom translation domain class::
+
+ from zope import interface
+
+ class TranslationDomain(object):
+ interface.implements(ITranslationDomain)
+
+ def translate(self, msgid, mapping=None, context=None,
+ target_language=None, default=None):
+
+ ...
+
+ component.provideUtility(TranslationDomain(), name="custom")
+
+This approach can be used to integrate other translation catalog
+implementations.
+
+.. highlight:: xml
+
+Namespace
+---------
+
+The ``i18n`` namespace URI and recommended prefix are currently
+defined as::
+
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+
+This is not a URL, but merely a unique identifier. Do not expect a
+browser to resolve it successfully.
+
+Statements
+----------
+
+The allowable ``i18n`` statements are:
+
+- ``i18n:translate``
+- ``i18n:domain``
+- ``i18n:source``
+- ``i18n:target``
+- ``i18n:name``
+- ``i18n:attributes``
+- ``i18n:data``
+
+``i18n:translate``
+^^^^^^^^^^^^^^^^^^
+
+This attribute is used to mark units of text for translation. If this
+attribute is specified with an empty string as the value, the message
+ID is computed from the content of the element bearing this attribute.
+Otherwise, the value of the element gives the message ID.
+
+``i18n:domain``
+^^^^^^^^^^^^^^^
+
+The ``i18n:domain`` attribute is used to specify the domain to be used
+to get the translation. If not specified, the translation services
+will use a default domain. The value of the attribute is used
+directly; it is not a TALES expression.
+
+``i18n:source``
+^^^^^^^^^^^^^^^
+
+The ``i18n:source`` attribute specifies the language of the text to be
+translated. The default is ``nothing``, which means we don't provide
+this information to the translation services.
+
+
+``i18n:target``
+^^^^^^^^^^^^^^^
+
+The ``i18n:target`` attribute specifies the language of the
+translation we want to get. If the value is ``default``, the language
+negotiation services will be used to choose the destination language.
+If the value is ``nothing``, no translation will be performed; this
+can be used to suppress translation within a larger translated unit.
+Any other value must be a language code.
+
+The attribute value is a TALES expression; the result of evaluating
+the expression is the language code or one of the reserved values.
+
+.. note:: ``i18n:target`` is primarily used for hints to text
+ extraction tools and translation teams. If you had some text that
+ should only be translated to e.g. German, then it probably
+ shouldn't be wrapped in an ``i18n:translate`` span.
+
+``i18n:name``
+^^^^^^^^^^^^^
+
+Name the content of the current element for use in interpolation
+within translated content. This allows a replaceable component in
+content to be re-ordered by translation. For example::
+
+ <span i18n:translate=''>
+ <span tal:replace='context.name' i18n:name='name' /> was born in
+ <span tal:replace='context.country_of_birth' i18n:name='country' />.
+ </span>
+
+would cause this text to be passed to the translation service::
+
+ "${name} was born in ${country}."
+
+``i18n:attributes``
+^^^^^^^^^^^^^^^^^^^
+
+This attribute will allow us to translate attributes of HTML tags,
+such as the ``alt`` attribute in the ``img`` tag. The
+``i18n:attributes`` attribute specifies a list of attributes to be
+translated with optional message IDs for each; if multiple attribute
+names are given, they must be separated by semicolons. Message IDs
+used in this context must not include whitespace.
+
+Note that the value of the particular attributes come either from the
+HTML attribute value itself or from the data inserted by
+``tal:attributes``.
+
+If an attibute is to be both computed using ``tal:attributes`` and
+translated, the translation service is passed the result of the TALES
+expression for that attribute.
+
+An example::
+
+ <img src="http://foo.com/logo" alt="Visit us"
+ tal:attributes="alt context.greeting"
+ i18n:attributes="alt"
+ >
+
+In this example, we let ``tal:attributes`` set the value of the ``alt``
+attribute to the text "Stop by for a visit!". This text will be
+passed to the translation service, which uses the result of language
+negotiation to translate "Stop by for a visit!" into the requested
+language. The example text in the template, "Visit us", will simply
+be discarded.
+
+Another example, with explicit message IDs::
+
+ <img src="../icons/uparrow.png" alt="Up"
+ i18n:attributes="src up-arrow-icon; alt up-arrow-alttext"
+ >
+
+Here, the message ID ``up-arrow-icon`` will be used to generate the
+link to an icon image file, and the message ID 'up-arrow-alttext' will
+be used for the "alt" text.
+
+``i18n:data``
+^^^^^^^^^^^^^
+
+Since TAL always returns strings, we need a way in ZPT to translate
+objects, one of the most obvious cases being ``datetime`` objects. The
+``data`` attribute will allow us to specify such an object, and
+``i18n:translate`` will provide us with a legal format string for that
+object. If ``data`` is used, ``i18n:translate`` must be used to give
+an explicit message ID, rather than relying on a message ID computed
+from the content.
+
+Relation with TAL processing
+----------------------------
+
+The attributes defined in the ``i18n`` namespace modify the behavior
+of the TAL interpreter for the ``tal:attributes``, ``tal:content``,
+``tal:repeat``, and ``tal:replace`` attributes, but otherwise do not
+affect TAL processing.
+
+Since these attributes only affect TAL processing by causing
+translations to occur at specific times, using these with a TAL
+processor which does not support the ``i18n`` namespace degrades well;
+the structural expectations for a template which uses the ``i18n``
+support is no different from those for a page which does not. The
+only difference is that translations will not be performed in a legacy
+processor.
+
+Relation with METAL processing
+-------------------------------
+
+When using translation with METAL macros, the internationalization
+context is considered part of the specific documents that page
+components are retrieved from rather than part of the combined page.
+This makes the internationalization context lexical rather than
+dynamic, making it easier for a site builder to understand the
+behavior of each element with respect to internationalization.
+
+Let's look at an example to see what this means::
+
+ <html i18n:translate='' i18n:domain='EventsCalendar'
+ metal:use-macro="container['master.html'].macros.thismonth">
+
+ <div metal:fill-slot='additional-notes'>
+ <ol tal:condition="context.notes">
+ <li tal:repeat="note context.notes">
+ <tal:block tal:omit-tag=""
+ tal:condition="note.heading">
+ <strong tal:content="note.heading">
+ Note heading goes here
+ </strong>
+ <br />
+ </tal:block>
+ <span tal:replace="note/description">
+ Some longer explanation for the note goes here.
+ </span>
+ </li>
+ </ol>
+ </div>
+
+ </html>
+
+And the macro source::
+
+ <html i18n:domain='CalendarService'>
+ <div tal:replace='python:DateTime().Month()'
+ i18n:translate=''>January</div>
+
+ <!-- really hairy TAL code here ;-) -->
+
+ <div define-slot="additional-notes">
+ Place for the application to add additional notes if desired.
+ </div>
+
+ </html>
+
+Note that the macro is using a different domain than the application
+(which it should be). With lexical scoping, no special markup needs
+to be applied to cause the slot-filler in the application to be part
+of the same domain as the rest of the application's page components.
+If dynamic scoping were used, the internationalization context would
+need to be re-established in the slot-filler.
+
+
+Extracting translatable message
+-------------------------------
+
+Translators use `PO files
+<http://www.gnu.org/software/hello/manual/gettext/PO-Files.html>`_
+when translating messages. To create and update PO files you need to
+do two things: *extract* all messages from python and templates files
+and store them in a ``.pot`` file, and for each language *update* its
+``.po`` file. Chameleon facilitates this by providing extractors for
+`Babel <http://babel.edgewall.org/>`_. To use this you need modify
+``setup.py``. For example:
+
+.. code-block:: python
+
+ from setuptools import setup
+
+ setup(name="mypackage",
+ install_requires = [
+ "Babel",
+ ],
+ message_extractors = { "src": [
+ ("**.py", "chameleon_python", None ),
+ ("**.pt", "chameleon_xml", None ),
+ ]},
+ )
+
+This tells Babel to scan the ``src`` directory while using the
+``chameleon_python`` extractor for all ``.py`` files and the
+``chameleon_xml`` extractor for all ``.pt`` files.
+
+You can now use Babel to manage your PO files:
+
+.. code-block:: bash
+
+ python setup.py extract_messages --output-file=i18n/mydomain.pot
+ python setup.py update_catalog \
+ -l nl \
+ -i i18n/mydomain.pot \
+ -o i18n/nl/LC_MESSAGES/mydomain.po
+ python setup.py compile_catalog \
+ --directory i18n --locale nl
+
+You can also configure default options in a ``setup.cfg`` file. For example::
+
+ [compile_catalog]
+ domain = mydomain
+ directory = i18n
+
+ [extract_messages]
+ copyright_holder = Acme Inc.
+ output_file = i18n/mydomain.pot
+ charset = UTF-8
+
+ [init_catalog]
+ domain = mydomain
+ input_file = i18n/mydomain.pot
+ output_dir = i18n
+
+ [update_catalog]
+ domain = mydomain
+ input_file = i18n/mydomain.pot
+ output_dir = i18n
+ previous = true
+
+You can now use the Babel commands directly::
+
+ python setup.py extract_messages
+ python setup.py update_catalog
+ python setup.py compile_catalog
+
+
+${...} operator
+###############
+
+The ``${...}`` notation is short-hand for text insertion. The
+Python-expression inside the braces is evaluated and the result
+included in the output (all inserted text is escaped by default):
+
+.. code-block:: html
+
+ <div id="section-${index + 1}">
+ ${content}
+ </div>
+
+To escape this behavior, prefix the notation with a backslash
+character: ``\${...}``.
+
+Note that if an object implements the ``__html__`` method, the result
+of this method will be inserted as-is (without XML escaping).
+
+Code blocks
+###########
+
+The ``<?python ... ?>`` notation allows you to embed Python code in
+templates:
+
+.. code-block:: html
+
+ <div>
+ <?python numbers = map(str, range(1, 10)) ?>
+ Please input a number from the range ${", ".join(numbers)}.
+ </div>
+
+The scope of name assignments is up to the nearest macro definition,
+or the template, if macros are not used.
+
+Note that code blocks can span multiple line and start on the next
+line of where the processing instruction begins:
+
+.. code-block:: html
+
+ <?python
+ foo = [1, 2, 3]
+ ?>
+
+You can use this to debug templates:
+
+.. code-block:: html
+
+ <div>
+ <?python import pdb; pdb.set_trace() ?>
+ </div>
+
+
+Markup comments
+###############
+
+You can apply the "!" and "?" modifiers to change how comments are
+processed:
+
+Drop
+
+ ``<!--! This comment will be dropped from output -->``
+
+Verbatim
+
+ ``<!--? This comment will be included verbatim -->``
+
+ That is, evaluation of ``${...}`` expressions is disabled if the
+ comment opens with the "?" character.
+
+
+.. _new-features:
+
+Language extensions
+###################
+
+Chameleon extends the *page template* language with a new expression
+types and language features. Some take inspiration from `Genshi
+<http://genshi.edgewall.org/>`_.
+
+ *New expression types*
+
+ The :ref:`structure <structure-expression>` expression wraps an
+ expression result as *structure*::
+
+ <div>${structure: body.text}</div>
+
+ The :ref:`import <import-expression>` expression imports module globals::
+
+ <div tal:define="compile import: re.compile">
+ ...
+ </div>
+
+ The :ref:`load <load-expression>` expression loads templates
+ relative to the current template::
+
+ <div tal:define="compile load: main.pt">
+ ...
+ </div>
+
+ *Tuple unpacking*
+
+ The ``tal:define`` and ``tal:repeat`` statements support tuple
+ unpacking::
+
+ tal:define="(a, b, c) [1, 2, 3]"
+
+ Extended `iterable unpacking
+ <http://www.python.org/dev/peps/pep-3132/>`_ using the asterisk
+ character is not currently supported (even for versions of
+ Python that support it natively).
+
+ *Dictionary lookup as fallback after attribute error*
+
+ If attribute lookup (using the ``obj.<name>`` syntax) raises an
+ ``AttributeError`` exception, a secondary lookup is attempted
+ using dictionary lookup --- ``obj['<name>']``.
+
+ Behind the scenes, this is done by rewriting all
+ attribute-lookups to a custom lookup call:
+
+ .. code-block:: python
+
+ def lookup_attr(obj, key):
+ try:
+ return getattr(obj, key)
+ except AttributeError as exc:
+ try:
+ get = obj.__getitem__
+ except AttributeError:
+ raise exc
+ try:
+ return get(key)
+ except KeyError:
+ raise exc
+
+ *Inline string substitution*
+
+ In element attributes and in the text or tail of an element,
+ string expression interpolation is available using the
+ ``${...}`` syntax::
+
+ <span class="content-${item_type}">
+ ${title or item_id}
+ </span>
+
+ *Code blocks*
+
+ Using ``<?python ... ?>`` notation, you can embed Python
+ statements in your templates:
+
+ .. code-block:: html
+
+ <div>
+ <?python numbers = map(str, range(1, 10)) ?>
+ Please input a number from the range ${", ".join(numbers)}.
+ </div>
+
+ *Literal content*
+
+ While the ``tal:content`` and ``tal:repeat`` attributes both
+ support the ``structure`` keyword which inserts the content as
+ a literal (without XML-escape), an object may also provide an
+ ``__html__`` method to the same effect.
+
+ The result of the method will be inserted as *structure*.
+
+ This is particularly useful for content which is substituted
+ using the expression operator: ``"${...}"`` since the
+ ``structure`` keyword is not allowed here.
+
+ *Switch statement*
+
+ Two new attributes have been added: ``tal:switch`` and
+ ``tal:case``. A case attribute works like a condition and only
+ allows content if the value matches that of the nearest parent
+ switch value.
+
+
+Incompatibilities and differences
+#################################
+
+There are a number of incompatibilities and differences between the
+Chameleon language implementation and the Zope reference
+implementation (ZPT):
+
+ *Default expression*
+
+ The default expression type is Python.
+
+ *Template arguments*
+
+ Arguments passed by keyword to the render- or call method are
+ inserted directly into the template execution namespace. This is
+ different from ZPT where these are only available through the
+ ``options`` dictionary.
+
+ Zope::
+
+ <div tal:content="options/title" />
+
+ Chameleon::
+
+ <div tal:content="title" />
+
+ *Special symbols*
+
+ The ``CONTEXTS`` symbol is not available.
+
+The `z3c.pt <http://pypi.python.org/pypi/z3c.pt>`_ package works as a
+compatibility layer. The template classes in this package provide a
+implementation which is fully compatible with ZPT.
+
+Notes
+#####
+
+.. [1] This has been changed in 2.x. Previously, it was up to the
+ expression engine to parse the expression values including any
+ semicolons and since for instance Python-expressions can never
+ end in a semicolon, it was possible to clearly distinguish
+ between the different uses of the symbol, e.g.
+
+ ::
+
+ tal:define="text 'Hello world; goodbye world'"
+
+ The semicolon appearing in the definition above is part of the
+ Python-expression simply because it makes the expression
+ valid. Meanwhile:
+
+ ::
+
+ tal:define="text1 'Hello world'; text2 'goodbye world'"
+
+ The semicolon here must denote a second variable definition
+ because there is no valid Python-expression that includes it.
+
+ While this behavior works well in practice, it is incompatible
+ with the reference specification, and also blurs the interface
+ between the compiler and the expression engine. In 2.x we
+ therefore have to escape the semicolon by doubling it (as
+ defined by the specification):
+
+ ::
+
+ tal:define="text 'Hello world;; goodbye world'"
+
diff --git a/lib/Chameleon-2.9.2/setup.cfg b/lib/Chameleon-2.9.2/setup.cfg
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/setup.cfg
@@ -0,0 +1,14 @@
+[easy_install]
+zip_ok = false
+
+[nosetests]
+match = ^test
+nocapture = 1
+cover-package = tree.codegen, tree.lexer, tree.parser, tree.nodes, tree.translation, tree.language, tree.tales, tree.expressions
+cover-erase = 1
+
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/lib/Chameleon-2.9.2/setup.py b/lib/Chameleon-2.9.2/setup.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/setup.py
@@ -0,0 +1,90 @@
+__version__ = '2.9.2'
+
+import os
+import sys
+
+try:
+ from distribute_setup import use_setuptools
+ use_setuptools()
+except: # doesn't work under tox/pip
+ pass
+
+from setuptools import setup, find_packages
+from setuptools.command.test import test
+
+here = os.path.abspath(os.path.dirname(__file__))
+try:
+ README = open(os.path.join(here, 'README.rst')).read()
+ CHANGES = open(os.path.join(here, 'CHANGES.rst')).read()
+except: # doesn't work under tox/pip
+ README = ''
+ CHANGES = ''
+
+install_requires = []
+
+version = sys.version_info[:3]
+if version < (2, 7, 0):
+ install_requires.append("ordereddict")
+ install_requires.append("unittest2")
+
+
+class Benchmark(test):
+ description = "Run benchmarks"
+ user_options = []
+ test_suite = None
+
+ def initialize_options(self):
+ """init options"""
+ pass
+
+ def finalize_options(self):
+ """finalize options"""
+
+ self.distribution.tests_require = [
+ 'zope.pagetemplate',
+ 'zope.component',
+ 'zope.i18n',
+ 'zope.testing']
+
+ def run(self):
+ test.run(self)
+ self.with_project_on_sys_path(self.run_benchmark)
+
+ def run_benchmark(self):
+ from chameleon import benchmark
+ print("running benchmark...")
+
+ benchmark.start()
+
+setup(
+ name="Chameleon",
+ version=__version__,
+ description="Fast HTML/XML Template Compiler.",
+ long_description="\n\n".join((README, CHANGES)),
+ classifiers=[
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Developers",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 2.5",
+ "Programming Language :: Python :: 2.6",
+ "Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3.1",
+ "Programming Language :: Python :: 3.2",
+ ],
+ author="Malthe Borch",
+ author_email="mborch at gmail.com",
+ url="http://www.pagetemplates.org/",
+ license='BSD-like (http://repoze.org/license.html)',
+ packages=find_packages('src'),
+ package_dir = {'': 'src'},
+ include_package_data=True,
+ install_requires=install_requires,
+ zip_safe=False,
+ test_suite="chameleon.tests",
+ cmdclass={
+ 'benchmark': Benchmark,
+ }
+ )
+
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO
@@ -0,0 +1,1122 @@
+Metadata-Version: 1.1
+Name: Chameleon
+Version: 2.9.2
+Summary: Fast HTML/XML Template Compiler.
+Home-page: http://www.pagetemplates.org/
+Author: Malthe Borch
+Author-email: mborch at gmail.com
+License: BSD-like (http://repoze.org/license.html)
+Description: Overview
+ ========
+
+ Chameleon is an HTML/XML template engine for `Python
+ <http://www.python.org>`_. It uses the *page templates* language.
+
+ You can use it in any Python web application with just about any
+ version of Python (2.5 and up, including 3.x and `pypy
+ <http://pypy.org>`_).
+
+ Visit the `website <http://pagetemplates.org>`_ for more information
+ or the `documentation <http://pagetemplates.org/docs/latest/>`_.
+
+ License and Copyright
+ ---------------------
+
+ This software is made available as-is under a BSD-like license [1]_
+ (see included copyright notice).
+
+
+ Notes
+ -----
+
+ .. [1] This software is licensed under the `Repoze
+ <http://repoze.org/license.html>`_ license.
+
+
+ Changes
+ =======
+
+ 2.9.2 (2012-06-06)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed a PyPy incompatibility.
+
+ - Fixed issue #109 which caused testing failures on some platforms.
+
+ 2.9.1 (2012-06-01)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue #103. The ``tal:on-error`` statement now always adds an
+ explicit end-tag to the element, even with a substitution content of
+ nothing.
+
+ - Fixed issue #113. The ``tal:on-error`` statement now works correctly
+ also for dynamic attributes. That is, the fallback tag now includes
+ only static attributes.
+
+ - Fixed name error which prevented the benchmark from running
+ correctly.
+
+ Compatibility:
+
+ - Fixed deprecation warning on Python 3 for zope interface implements
+ declaration. This fixes issue #116.
+
+ 2.9.0 (2012-05-31)
+ ------------------
+
+ Features:
+
+ - The translation function now gets the ``econtext`` argument as the
+ value for ``context``. Note that historically, this was usually an
+ HTTP request which might provide language negotiation data through a
+ dictionary interface.
+ [alvinyue]
+
+ Bugfixes:
+
+ - Fixed import alias issue which would lead to a syntax error in
+ generated Python code. Fixes issue #114.
+
+ 2.8.5 (2012-05-02)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed minor installation issues on Python 2.5 and 3.
+ [ppaez]
+
+ - Ensure output is unicode even when trivial (an empty string).
+
+ 2.8.4 (2012-04-18)
+ ------------------
+
+ Features:
+
+ - In exception output, long filenames are now truncated to 60
+ characters of output, preventing line wrap which makes it difficult
+ to scan the exception output.
+
+ Bugfixes:
+
+ - Include filename and location in exception output for exceptions
+ raised during compilation.
+
+ - If a trivial translation substitution variable is given (i.e. an
+ empty string), simply ignore it. This fixes issue #106.
+
+ 2.8.3 (2012-04-16)
+ ------------------
+
+ Features:
+
+ - Log template source on debug-level before cooking.
+
+ - The `target_language` argument, if given, is now available as a
+ variable in templates.
+
+ 2.8.2 (2012-03-30)
+ ------------------
+
+ Features:
+
+ - Temporary caches used in debug mode are cleaned up eagerly, rather
+ than waiting for process termination.
+ [mitchellrj]
+
+ Bugfixes:
+
+ - The `index`, `start` and `end` methods on the TAL repeat object are
+ now callable. This fixes an incompatibility with ZPT.
+
+ - The loader now correctly handles absolute paths on Windows.
+ [rdale]
+
+ 2.8.1 (2012-03-29)
+ ------------------
+
+ Features:
+
+ - The exception formatter now lists errors in 'wrapping order'. This
+ means that the innermost, and presumably most relevant exception is
+ shown last.
+
+ Bugfixes:
+
+ - The exception formatter now correctly recognizes nested errors and
+ does not rewrap the dynamically generated exception class.
+
+ - The exception formatter now correctly sets the ``__module__``
+ attribute to that of the original exception class.
+
+ 2.8.0 (2012-02-29)
+ ------------------
+
+ Features:
+
+ - Added support for code blocks using the `<?python ... ?>` processing
+ instruction syntax.
+
+ The scope is name assignments is up until the nearest macro
+ definition, or the template itself if macros are not used.
+
+ Bugfixes:
+
+ - Fall back to the exception class' ``__new__`` method to safely
+ create an exception object that is not implemented in Python.
+
+ - The exception formatter now keeps track of already formatted
+ exceptions, and ignores them from further output.
+
+ 2.7.4 (2012-02-27)
+ ------------------
+
+ - The error handler now invokes the ``__init__`` method of
+ ``BaseException`` instead of the possibly overriden method (which
+ may take required arguments). This fixes issue #97.
+ [j23d, malthe]
+
+ 2.7.3 (2012-01-16)
+ ------------------
+
+ Bugfixes:
+
+ - The trim whitespace option now correctly trims actual whitespace to
+ a single character, appearing either to the left or to the right of
+ an element prefix or suffix string.
+
+ 2.7.2 (2012-01-08)
+ ------------------
+
+ Features:
+
+ - Added option ``trim_attribute_space`` that decides whether attribute
+ whitespace is stripped (at most down to a single space). This option
+ exists to provide compatibility with the reference
+ implementation. Fixes issue #85.
+
+ Bugfixes:
+
+ - Ignore unhashable builtins when generating a reverse builtin
+ map to quickly look up a builtin value.
+ [malthe]
+
+ - Apply translation mapping even when a translation function is not
+ available. This fixes issue #83.
+ [malthe]
+
+ - Fixed issue #80. The translation domain for a slot is defined by the
+ source document, i.e. the template providing the content for a slot
+ whether it be the default or provided through ``metal:fill-slot``.
+ [jcbrand]
+
+ - In certain circumstances, a Unicode non-breaking space character would cause
+ a define clause to fail to parse.
+
+ 2.7.1 (2011-12-29)
+ ------------------
+
+ Features:
+
+ - Enable expression interpolation in CDATA.
+
+ - The page template class now implements dictionary access to macros::
+
+ template[name]
+
+ This is a short-hand for::
+
+ template.macros[name]
+
+ Bugfixes:
+
+ - An invalid define clause would be silently ignored; we now raise a
+ language error exception. This fixes issue #79.
+
+ - Fixed regression where ``${...}`` interpolation expressions could
+ not span multiple lines. This fixes issue #77.
+
+ 2.7.0 (2011-12-13)
+ ------------------
+
+ Features:
+
+ - The ``load:`` expression now derives from the string expression such
+ that the ``${...}`` operator can be used for expression
+ interpolation.
+
+ - The ``load:`` expression now accepts asset specs; these are resolved
+ by the ``pkg_resources.resource_filename`` function::
+
+ <package_name>:<path>
+
+ An example from the test suite::
+
+ chameleon:tests/inputs/hello_world.pt
+
+ Bugfixes:
+
+ - If an attribute name for translation was not a valid Python
+ identifier, the compiler would generate invalid code. This has been
+ fixed, and the compiler now also throws an exception if an attribute
+ specification contains a comma. (Note that the only valid separator
+ character is the semicolon, when specifying attributes for
+ translation via the ``i18n:translate`` statement). This addresses
+ issue #76.
+
+ 2.6.2 (2011-12-08)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue where ``tal:on-error`` would not respect
+ ``tal:omit-tag`` or namespace elements which are omitted by default
+ (such as ``<tal:block />``).
+
+ - Fixed issue where ``macros`` attribute would not be available on
+ file-based templates due to incorrect initialization.
+
+ - The ``TryExcept`` and ``TryFinally`` AST nodes are not available on
+ Python 3.3. These have been aliased to ``Try``. This fixes issue
+ #75.
+
+ Features:
+
+ - The TAL repeat item now makes a security declaration that grants
+ access to unprotected subobjects on the Zope 2 platform::
+
+ __allow_access_to_unprotected_subobjects__ = True
+
+ This is required for legacy compatibility and does not affect other
+ environments.
+
+ - The template object now has a method ``write(body)`` which
+ explicitly decodes and cooks a string input.
+
+ - Added configuration option ``loader_class`` which sets the class
+ used to create the template loader object.
+
+ The class (essentially a callable) is created at template
+ construction time.
+
+ 2.6.1 (2011-11-30)
+ ------------------
+
+ Bugfixes:
+
+ - Decode HTML entities in expression interpolation strings. This fixes
+ issue #74.
+
+ - Allow ``xml`` and ``xmlns`` attributes on TAL, I18N and METAL
+ namespace elements. This fixes issue #73.
+
+ 2.6.0 (2011-11-24)
+ ------------------
+
+ Features:
+
+ - Added support for implicit translation:
+
+ The ``implicit_i18n_translate`` option enables implicit translation
+ of text. The ``implicit_i18n_attributes`` enables implicit
+ translation of attributes. The latter must be a set and for an
+ attribute to be implicitly translated, its lowercase string value
+ must be included in the set.
+
+ - Added option ``strict`` (enabled by default) which decides whether
+ expressions are required to be valid at compile time. That is, if
+ not set, an exception is only raised for an invalid expression at
+ evaluation time.
+
+ - An expression error now results in an exception only if the
+ expression is attempted evaluated during a rendering.
+
+ - Added a configuration option ``prepend_relative_search_path`` which
+ decides whether the path relative to a file-based template is
+ prepended to the load search path. The default is ``True``.
+
+ - Added a configuration option ``search_path`` to the file-based
+ template class, which adds additional paths to the template load
+ instance bound to the ``load:`` expression. The option takes a
+ string path or an iterable yielding string paths. The default value
+ is the empty set.
+
+ Bugfixes:
+
+ - Exception instances now support pickle/unpickle.
+
+ - An attributes in i18n:attributes no longer needs to match an
+ existing or dynamic attribute in order to appear in the
+ element. This fixes issue #66.
+
+ 2.5.3 (2011-10-23)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue where a nested macro slot definition would fail even
+ though there existed a parent macro definition. This fixes issue
+ #69.
+
+ 2.5.2 (2011-10-12)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue where technically invalid input would result in a
+ compiler error.
+
+ Features:
+
+ - The markup class now inherits from the unicode string type such that
+ it's compatible with the string interface.
+
+ 2.5.1 (2011-09-29)
+ ------------------
+
+ Bugfixes:
+
+ - The symbol names "convert", "decode" and "translate" are now no
+ longer set as read-only *compiler internals*. This fixes issue #65.
+
+ - Fixed an issue where a macro extension chain nested two levels (a
+ template uses a macro that extends a macro) would lose the middle
+ slot definitions if slots were defined nested.
+
+ The compiler now throws an error if a nested slot definition is used
+ outside a macro extension context.
+
+ 2.5.0 (2011-09-23)
+ ------------------
+
+ Features:
+
+ - An expression type ``structure:`` is now available which wraps the
+ expression result as *structure* such that it is not escaped on
+ insertion, e.g.::
+
+ <div id="content">
+ ${structure: context.body}
+ </div>
+
+ This also means that the ``structure`` keyword for ``tal:content``
+ and ``tal:replace`` now has an alternative spelling via the
+ expression type ``structure:``.
+
+ - The string-based template constructor now accepts encoded input.
+
+ 2.4.6 (2011-09-23)
+ ------------------
+
+ Bugfixes:
+
+ - The ``tal:on-error`` statement should catch all exceptions.
+
+ - Fixed issue that would prevent escaping of interpolation expression
+ values appearing in text.
+
+ 2.4.5 (2011-09-21)
+ ------------------
+
+ Bugfixes:
+
+ - The ``tal:on-error`` handler should have a ``error`` variable
+ defined that has the value of the exception thrown.
+
+ - The ``tal:on-error`` statement is a substitution statement and
+ should support the "text" and "structure" insertion methods.
+
+ 2.4.4 (2011-09-15)
+ ------------------
+
+ Bugfixes:
+
+ - An encoding specified in the XML document preamble is now read and
+ used to decode the template input to unicode. This fixes issue #55.
+
+ - Encoded expression input on Python 3 is now correctly
+ decoded. Previously, the string representation output would be
+ included instead of an actually decoded string.
+
+ - Expression result conversion steps are now correctly included in
+ error handling such that the exception output points to the
+ expression location.
+
+ 2.4.3 (2011-09-13)
+ ------------------
+
+ Features:
+
+ - When an encoding is provided, pass the 'ignore' flag to avoid
+ decoding issues with bad input.
+
+ Bugfixes:
+
+ - Fixed pypy compatibility issue (introduced in previous release).
+
+ 2.4.2 (2011-09-13)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue in the compiler where an internal variable (such as a
+ translation default value) would be cached, resulting in variable
+ scope corruption (see issue #49).
+
+ 2.4.1 (2011-09-08)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed an issue where a default value for an attribute would
+ sometimes spill over into another attribute.
+
+ - Fixed issue where the use of the ``default`` name in an attribute
+ interpolation expression would print the attribute value. This is
+ unexpected, because it's an expression, not a static text suitable
+ for output. An attribute value of ``default`` now correctly drops
+ the attribute.
+
+ 2.4.0 (2011-08-22)
+ ------------------
+
+ Features:
+
+ - Added an option ``boolean_attributes`` to evaluate and render a
+ provided set of attributes using a boolean logic: if the attribute
+ is a true value, the value will be the attribute name, otherwise the
+ attribute is dropped.
+
+ In the reference implementation, the following attributes are
+ configured as boolean values when the template is rendered in
+ HTML-mode::
+
+ "compact", "nowrap", "ismap", "declare", "noshade",
+ "checked", "disabled", "readonly", "multiple", "selected",
+ "noresize", "defer"
+
+ Note that in Chameleon, these attributes must be manually provided.
+
+ Bugfixes:
+
+ - The carriage return character (used on Windows platforms) would
+ incorrectly be included in Python comments.
+
+ It is now replaced with a line break.
+
+ This fixes issue #44.
+
+ 2.3.8 (2011-08-19)
+ ------------------
+
+ - Fixed import error that affected Python 2.5 only.
+
+ 2.3.7 (2011-08-19)
+ ------------------
+
+ Features:
+
+ - Added an option ``literal_false`` that disables the default behavior
+ of dropping an attribute for a value of ``False`` (in addition to
+ ``None``). This modified behavior is the behavior exhibited in
+ reference implementation.
+
+ Bugfixes:
+
+ - Undo attribute special HTML attribute behavior (see previous
+ release).
+
+ This turned out not to be a compatible behavior; rather, boolean
+ values should simply be coerced to a string.
+
+ Meanwhile, the reference implementation does support an HTML mode in
+ which the special attribute behavior is exhibited.
+
+ We do not currently support this mode.
+
+ 2.3.6 (2011-08-18)
+ ------------------
+
+ Features:
+
+ - Certain HTML attribute names now have a special behavior for a
+ attribute value of ``True`` (or ``default`` if no default is
+ defined). For these attributes, this return value will result in the
+ name being printed as the value::
+
+ <input type="input" tal:attributes="checked True" />
+
+ will be rendered as::
+
+ <input type="input" checked="checked" />
+
+ This behavior is compatible with the reference implementation.
+
+ 2.3.5 (2011-08-18)
+ ------------------
+
+ Features:
+
+ - Added support for the set operator (``{item, item, ...}``).
+
+ Bugfixes:
+
+ - If macro is defined on the same element as a translation name, this
+ no longer results in a "translation name not allowed outside
+ translation" error. This fixes issue #43.
+
+ - Attribute fallback to dictionary lookup now works on multiple items
+ (e.g. ``d1.d2.d2``). This fixes issue #42.
+
+ 2.3.4 (2011-08-16)
+ ------------------
+
+ Features:
+
+ - When inserting content in either attributes or text, a value of
+ ``True`` (like ``False`` and ``None``) will result in no
+ action.
+
+ - Use statically assigned variables for ``"attrs"`` and
+ ``"default"``. This change yields a performance improvement of
+ 15-20%.
+
+ - The template loader class now accepts an optional argument
+ ``default_extension`` which accepts a filename extension which will
+ be appended to the filename if there's not already an extension.
+
+ Bugfixes:
+
+ - The default symbol is now ``True`` for an attribute if the attribute
+ default is not provided. Note that the result is that the attribute
+ is dropped. This fixes issue #41.
+
+ - Fixed an issue where assignment to a variable ``"type"`` would
+ fail. This fixes issue #40.
+
+ - Fixed an issue where an (unsuccesful) assignment for a repeat loop
+ to a compiler internal name would not result in an error.
+
+ - If the translation function returns the identical object, manually
+ coerce it to string. This fixes a compatibility issue with
+ translation functions which do not convert non-string objects to a
+ string value, but simply return them unchanged.
+
+ 2.3.3 (2011-08-15)
+ ------------------
+
+ Features:
+
+ - The ``load:`` expression now passes the initial keyword arguments to
+ its template loader (e.g. ``auto_reload`` and ``encoding``).
+
+ - In the exception output, string variable values are now limited to a
+ limited output of characters, single line only.
+
+ Bugfixes:
+
+ - Fixed horizontal alignment of exception location info
+ (i.e. 'String:', 'Filename:' and 'Location:') such that they match
+ the template exception formatter.
+
+ 2.3.2 (2011-08-11)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue where i18n:domain would not be inherited through macros
+ and slots. This fixes issue #37.
+
+ 2.3.1 (2011-08-11)
+ ------------------
+
+ Features:
+
+ - The ``Builtin`` node type may now be used to represent any Python
+ local or global name. This allows expression compilers to refer to
+ e.g. ``get`` or ``getitem``, or to explicit require a builtin object
+ such as one from the ``extra_builtins`` dictionary.
+
+ Bugfixes:
+
+ - Builtins which are not explicitly disallowed may now be redefined
+ and used as variables (e.g. ``nothing``).
+
+ - Fixed compiler issue with circular node annotation loop.
+
+ 2.3 (2011-08-10)
+ ----------------
+
+ Features:
+
+ - Added support for the following syntax to disable inline evaluation
+ in a comment:
+
+ <!--? comment appears verbatim (no ${...} evaluation) -->
+
+ Note that the initial question mark character (?) will be omitted
+ from output.
+
+ - The parser now accepts '<' and '>' in attributes. Note that this is
+ invalid markup. Previously, the '<' would not be accepted as a valid
+ attribute value, but this would result in an 'unexpected end tag'
+ error elsewhere. This fixes issue #38.
+
+ - The expression compiler now provides methods ``assign_text`` and
+ ``assign_value`` such that a template engine might configure this
+ value conversion to support e.g. encoded strings.
+
+ Note that currently, the only client for the ``assign_text`` method
+ is the string expression type.
+
+ - Enable template loader for string-based template classes. Note that
+ the ``filename`` keyword argument may be provided on initialization
+ to identify the template source by filename. This fixes issue #36.
+
+ - Added ``extra_builtins`` option to the page template class. These
+ builtins are added to the default builtins dictionary at cook time
+ and may be provided at initialization using the ``extra_builtins``
+ keyword argument.
+
+ Bugfixes:
+
+ - If a translation domain is set for a fill slot, use this setting
+ instead of the macro template domain.
+
+ - The Python expression compiler now correctly decodes HTML entities
+ ``'gt'`` and ``'lt'``. This fixes issue #32.
+
+ - The string expression compiler now correctly handles encoded text
+ (when support for encoded strings is enabled). This fixes issue #35.
+
+ - Fixed an issue where setting the ``filename`` attribute on a
+ file-based template would not automatically cause an invalidation.
+
+ - Exceptions raised by Chameleon can now be copied via
+ ``copy.copy``. This fixes issue #36.
+ [leorochael]
+
+ - If copying the exception fails in the exception handler, simply
+ re-raise the original exception and log a warning.
+
+ 2.2 (2011-07-28)
+ ----------------
+
+ Features:
+
+ - Added new expression type ``load:`` that allows loading a
+ template. Both relative and absolute paths are supported. If the
+ path given is relative, then it will be resolved with respect to the
+ directory of the template.
+
+ - Added support for dynamic evaluation of expressions.
+
+ Note that this is to support legacy applications. It is not
+ currently wired into the provided template classes.
+
+ - Template classes now have a ``builtins`` attribute which may be used
+ to define built-in variables always available in the template
+ variable scope.
+
+ Incompatibilities:
+
+ - The file-based template class no longer accepts a parameter
+ ``loader``. This parameter would be used to load a template from a
+ relative path, using a ``find(filename)`` method. This was however,
+ undocumented, and probably not very useful since we have the
+ ``TemplateLoader`` mechanism already.
+
+ - The compiled template module now contains an ``initialize`` function
+ which takes values that map to the template builtins. The return
+ value of this function is a dictionary that contains the render
+ functions.
+
+ Bugfixes:
+
+ - The file-based template class no longer verifies the existance of a
+ template file (using ``os.lstat``). This now happens implicitly if
+ eager parsing is enabled, or otherwise when first needed (e.g. at
+ render time).
+
+ This is classified as a bug fix because the previous behavior was
+ probably not what you'd expect, especially if an application
+ initializes a lot of templates without needing to render them
+ immediately.
+
+ 2.1.1 (2011-07-28)
+ ------------------
+
+ Features:
+
+ - Improved exception display. The expression string is now shown in
+ the context of the original source (if available) with a marker
+ string indicating the location of the expression in the template
+ source.
+
+ Bugfixes:
+
+ - The ``structure`` insertion mode now correctly decodes entities for
+ any expression type (including ``string:``). This fixes issue #30.
+
+ - Don't show internal variables in the exception formatter variable
+ listing.
+
+ 2.1 (2011-07-25)
+ ----------------
+
+ Features:
+
+ - Expression interpolation (using the ``${...}`` operator and
+ previously also ``$identifier``) now requires braces everywhere
+ except inside the ``string:`` expression type.
+
+ This change is motivated by a number of legacy templates in which
+ the interpolation format without braces ``$identifier`` appears as
+ text.
+
+ 2.0.2 (2011-07-25)
+ ------------------
+
+ Bugfixes:
+
+ - Don't use dynamic variable scope for lambda-scoped variables (#27).
+
+ - Avoid duplication of exception class and message in traceback.
+
+ - Fixed issue where a ``metal:fill-slot`` would be ignored if a macro
+ was set to be used on the same element (#16).
+
+ 2.0.1 (2011-07-23)
+ ------------------
+
+ Bugfixes:
+
+ - Fixed issue where global variable definition from macro slots would
+ fail (they would instead be local). This also affects error
+ reporting from inside slots because this would be recorded
+ internally as a global.
+
+ - Fixed issue with template cache digest (used for filenames); modules
+ are now invalidated whenever any changes are made to the
+ distribution set available (packages on ``sys.path``).
+
+ - Fixed exception handler to better let exceptions propagate through
+ the renderer.
+
+ - The disk-based module compiler now mangles template source filenames
+ such that the output Python module is valid and at root level (dots
+ and hyphens are replaced by an underscore). This fixes issue #17.
+
+ - Fixed translations (i18n) on Python 2.5.
+
+ 2.0 (2011-07-14)
+ ----------------
+
+ - Point release.
+
+ 2.0-rc14 (2011-07-13)
+ ---------------------
+
+ Bugfixes:
+
+ - The tab character (``\t``) is now parsed correctly when used inside
+ tags.
+
+ Features:
+
+ - The ``RepeatDict`` class now works as a proxy behind a seperate
+ dictionary instance.
+
+ - Added template constructor option ``keep_body`` which is a flag
+ (also available as a class attribute) that controls whether to save
+ the template body input in the ``body`` attribute.
+
+ This is disabled by default, unless debug-mode is enabled.
+
+ - The page template loader class now accepts an optional ``formats``
+ argument which can be used to select an alternative template class.
+
+ 2.0-rc13 (2011-07-07)
+ ---------------------
+
+ Bugfixes:
+
+ - The backslash character (followed by optional whitespace and a line
+ break) was not correctly interpreted as a continuation for Python
+ expressions.
+
+ Features:
+
+ - The Python expression implementation is now more flexible for
+ external subclassing via a new ``parse`` method.
+
+ 2.0-rc12 (2011-07-04)
+ ---------------------
+
+ Bugfixes:
+
+ - Initial keyword arguments passed to a template now no longer "leak"
+ into the template variable space after a macro call.
+
+ - An unexpected end tag is now an unrecoverable error.
+
+ Features:
+
+ - Improve exception output.
+
+ 2.0-rc11 (2011-05-26)
+ ---------------------
+
+ Bugfixes:
+
+ - Fixed issue where variable names that begin with an underscore were
+ seemingly allowed, but their use resulted in a compiler error.
+
+ Features:
+
+ - Template variable names are now allowed to be prefixed with a single
+ underscore, but not two or more (reserved for internal use).
+
+ Examples of valid names::
+
+ item
+ ITEM
+ _item
+ camelCase
+ underscore_delimited
+ help
+
+ - Added support for Genshi's comment "drop" syntax::
+
+ <!--! This comment will be dropped -->
+
+ Note the additional exclamation (!) character.
+
+ This fixes addresses issue #10.
+
+ 2.0-rc10 (2011-05-24)
+ ---------------------
+
+ Bugfixes:
+
+ - The ``tal:attributes`` statement now correctly operates
+ case-insensitive. The attribute name given in the statement will
+ replace an existing attribute with the same name, without respect to
+ case.
+
+ Features:
+
+ - Added ``meta:interpolation`` statement to control expression
+ interpolation setting.
+
+ Strings that disable the setting: ``"off"`` and ``"false"``.
+ Strings that enable the setting: ``"on"`` and ``"true"``.
+
+ - Expression interpolation now works inside XML comments.
+
+ 2.0-rc9 (2011-05-05)
+ --------------------
+
+ Features:
+
+ - Better debugging support for string decode and conversion. If a
+ naive join fails, each element in the output will now be attempted
+ coerced to unicode to try and trigger the failure near to the bad
+ string.
+
+ 2.0-rc8 (2011-04-11)
+ --------------------
+
+ Bugfixes:
+
+ - If a macro defines two slots with the same name, a caller will now
+ fill both with a single usage.
+
+ - If a valid of ``None`` is provided as the translation function
+ argument, we now fall back to the class default.
+
+ 2.0-rc7 (2011-03-29)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed issue with Python 2.5 compatibility AST. This affected at
+ least PyPy 1.4.
+
+ Features:
+
+ - The ``auto_reload`` setting now defaults to the class value; the
+ base template class gives a default value of
+ ``chameleon.config.AUTO_RELOAD``. This change allows a subclass to
+ provide a custom default value (such as an application-specific
+ debug mode setting).
+
+
+ 2.0-rc6 (2011-03-19)
+ --------------------
+
+ Features:
+
+ - Added support for ``target_language`` keyword argument to render
+ method. If provided, the argument will be curried onto the
+ translation function.
+
+ Bugfixes:
+
+ - The HTML entities 'lt', 'gt' and 'quot' appearing inside content
+ subtition expressions are now translated into their native character
+ values. This fixes an issue where you could not dynamically create
+ elements using the ``structure`` (which is possible in ZPT). The
+ need to create such structure stems from the lack of an expression
+ interpolation operator in ZPT.
+
+ - Fixed duplicate file pointer issue with test suite (affected Windows
+ platforms only). This fixes issue #9.
+ [oliora]
+
+ - Use already open file using ``os.fdopen`` when trying to write out
+ the module source. This fixes LP #731803.
+
+
+ 2.0-rc5 (2011-03-07)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed a number of issues concerning the escaping of attribute
+ values:
+
+ 1) Static attribute values are now included as they appear in the
+ source.
+
+ This means that invalid attribute values such as ``"true &&
+ false"`` are now left alone. It's not the job of the template
+ engine to correct such markup, at least not in the default mode
+ of operation.
+
+ 2) The string expression compiler no longer unescapes
+ values. Instead, this is left to each expression
+ compiler. Currently only the Python expression compiler unescapes
+ its input.
+
+ 3) The dynamic escape code sequence now correctly only replaces
+ ampersands that are part of an HTML escape format.
+
+ Imports:
+
+ - The page template classes and the loader class can now be imported
+ directly from the ``chameleon`` module.
+
+ Features:
+
+ - If a custom template loader is not provided, relative paths are now
+ resolved using ``os.abspath`` (i.e. to the current working
+ directory).
+
+ - Absolute paths are normalized using ``os.path.normpath`` and
+ ``os.path.expanduser``. This ensures that all paths are kept in
+ their "canonical" form.
+
+
+ 2.0-rc4 (2011-03-03)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed an issue where the output of an end-to-end string expression
+ would raise an exception if the expression evaluated to ``None`` (it
+ should simply output nothing).
+
+ - The ``convert`` function (which is configurable on the template
+ class level) now defaults to the ``translate`` function (at
+ run-time).
+
+ This fixes an issue where message objects were not translated (and
+ thus converted to a string) using the a provided ``translate``
+ function.
+
+ - Fixed string interpolation issue where an expression immediately
+ succeeded by a right curly bracket would not parse.
+
+ This fixes issue #5.
+
+ - Fixed error where ``tal:condition`` would be evaluated after
+ ``tal:repeat``.
+
+ Features:
+
+ - Python expression is now a TALES expression. That means that the
+ pipe operator can be used to chain two or more expressions in a
+ try-except sequence.
+
+ This behavior was ported from the 1.x series. Note that while it's
+ still possible to use the pipe character ("|") in an expression, it
+ must now be escaped.
+
+ - The template cache can now be shared by multiple processes.
+
+
+ 2.0-rc3 (2011-03-02)
+ --------------------
+
+ Bugfixes:
+
+ - Fixed ``atexit`` handler.
+
+ This fixes issue #3.
+
+ - If a cache directory is specified, it will now be used even when not
+ in debug mode.
+
+ - Allow "comment" attribute in the TAL namespace.
+
+ This fixes an issue in the sense that the reference engine allows
+ any attribute within the TAL namespace. However, only "comment" is
+ in common use.
+
+ - The template constructor now accepts a flag ``debug`` which puts the
+ template *instance* into debug-mode regardless of the global
+ setting.
+
+ This fixes issue #1.
+
+ Features:
+
+ - Added exception handler for exceptions raised while evaluating an
+ expression.
+
+ This handler raises (or attempts to) a new exception of the type
+ ``RenderError``, with an additional base class of the original
+ exception class. The string value of the exception is a formatted
+ error message which includes the expression that caused the
+ exception.
+
+ If we are unable to create the exception class, the original
+ exception is re-raised.
+
+ 2.0-rc2 (2011-02-28)
+ --------------------
+
+ - Fixed upload issue.
+
+ 2.0-rc1 (2011-02-28)
+ --------------------
+
+ - Initial public release. See documentation for what's new in this
+ series.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt
@@ -0,0 +1,380 @@
+.gitignore
+CHANGES.rst
+COPYRIGHT.txt
+LICENSE.txt
+Makefile
+README.rst
+distribute_setup.py
+setup.cfg
+setup.py
+tox.ini
+benchmarks/bm_chameleon.py
+benchmarks/bm_mako.py
+benchmarks/util.py
+docs/conf.py
+docs/configuration.rst
+docs/index.rst
+docs/integration.rst
+docs/library.rst
+docs/reference.rst
+src/Chameleon.egg-info/PKG-INFO
+src/Chameleon.egg-info/SOURCES.txt
+src/Chameleon.egg-info/dependency_links.txt
+src/Chameleon.egg-info/not-zip-safe
+src/Chameleon.egg-info/top_level.txt
+src/chameleon/__init__.py
+src/chameleon/ast24.py
+src/chameleon/astutil.py
+src/chameleon/benchmark.py
+src/chameleon/codegen.py
+src/chameleon/compiler.py
+src/chameleon/config.py
+src/chameleon/exc.py
+src/chameleon/i18n.py
+src/chameleon/interfaces.py
+src/chameleon/loader.py
+src/chameleon/metal.py
+src/chameleon/namespaces.py
+src/chameleon/nodes.py
+src/chameleon/parser.py
+src/chameleon/program.py
+src/chameleon/py25.py
+src/chameleon/py26.py
+src/chameleon/tal.py
+src/chameleon/tales.py
+src/chameleon/template.py
+src/chameleon/tokenize.py
+src/chameleon/utils.py
+src/chameleon/tests/__init__.py
+src/chameleon/tests/test_doctests.py
+src/chameleon/tests/test_loader.py
+src/chameleon/tests/test_parser.py
+src/chameleon/tests/test_sniffing.py
+src/chameleon/tests/test_templates.py
+src/chameleon/tests/test_tokenizer.py
+src/chameleon/tests/inputs/001-interpolation.txt
+src/chameleon/tests/inputs/001-variable-scope.html
+src/chameleon/tests/inputs/001-variable-scope.pt
+src/chameleon/tests/inputs/001.xml
+src/chameleon/tests/inputs/002-repeat-scope.pt
+src/chameleon/tests/inputs/002.xml
+src/chameleon/tests/inputs/003-content.pt
+src/chameleon/tests/inputs/003.xml
+src/chameleon/tests/inputs/004-attributes.pt
+src/chameleon/tests/inputs/004.xml
+src/chameleon/tests/inputs/005-default.pt
+src/chameleon/tests/inputs/005.xml
+src/chameleon/tests/inputs/006-attribute-interpolation.pt
+src/chameleon/tests/inputs/006.xml
+src/chameleon/tests/inputs/007-content-interpolation.pt
+src/chameleon/tests/inputs/007.xml
+src/chameleon/tests/inputs/008-builtins.pt
+src/chameleon/tests/inputs/008.xml
+src/chameleon/tests/inputs/009-literals.pt
+src/chameleon/tests/inputs/009.xml
+src/chameleon/tests/inputs/010-structure.pt
+src/chameleon/tests/inputs/010.xml
+src/chameleon/tests/inputs/011-messages.pt
+src/chameleon/tests/inputs/011.xml
+src/chameleon/tests/inputs/012-translation.pt
+src/chameleon/tests/inputs/012.xml
+src/chameleon/tests/inputs/013-repeat-nested.pt
+src/chameleon/tests/inputs/013.xml
+src/chameleon/tests/inputs/014-repeat-nested-similar.pt
+src/chameleon/tests/inputs/014.xml
+src/chameleon/tests/inputs/015-translation-nested.pt
+src/chameleon/tests/inputs/015.xml
+src/chameleon/tests/inputs/016-explicit-translation.pt
+src/chameleon/tests/inputs/016.xml
+src/chameleon/tests/inputs/017-omit-tag.pt
+src/chameleon/tests/inputs/017.xml
+src/chameleon/tests/inputs/018-translation-nested-dynamic.pt
+src/chameleon/tests/inputs/018.xml
+src/chameleon/tests/inputs/019-replace.pt
+src/chameleon/tests/inputs/019.xml
+src/chameleon/tests/inputs/020-on-error.pt
+src/chameleon/tests/inputs/020.xml
+src/chameleon/tests/inputs/021-translation-domain.pt
+src/chameleon/tests/inputs/021.xml
+src/chameleon/tests/inputs/022-switch.pt
+src/chameleon/tests/inputs/022.xml
+src/chameleon/tests/inputs/023-condition.pt
+src/chameleon/tests/inputs/023.xml
+src/chameleon/tests/inputs/024-namespace-elements.pt
+src/chameleon/tests/inputs/024.xml
+src/chameleon/tests/inputs/025-repeat-whitespace.pt
+src/chameleon/tests/inputs/025.xml
+src/chameleon/tests/inputs/026-repeat-variable.pt
+src/chameleon/tests/inputs/026.xml
+src/chameleon/tests/inputs/027-attribute-replacement.pt
+src/chameleon/tests/inputs/027.xml
+src/chameleon/tests/inputs/028-attribute-toggle.pt
+src/chameleon/tests/inputs/028.xml
+src/chameleon/tests/inputs/029-attribute-ordering.pt
+src/chameleon/tests/inputs/029.xml
+src/chameleon/tests/inputs/030-repeat-tuples.pt
+src/chameleon/tests/inputs/030.xml
+src/chameleon/tests/inputs/031-namespace-with-tal.pt
+src/chameleon/tests/inputs/031.xml
+src/chameleon/tests/inputs/032-master-template.pt
+src/chameleon/tests/inputs/032.xml
+src/chameleon/tests/inputs/033-use-macro-trivial.pt
+src/chameleon/tests/inputs/033.xml
+src/chameleon/tests/inputs/034-use-template-as-macro.pt
+src/chameleon/tests/inputs/034.xml
+src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt
+src/chameleon/tests/inputs/035.xml
+src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt
+src/chameleon/tests/inputs/036.xml
+src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt
+src/chameleon/tests/inputs/037.xml
+src/chameleon/tests/inputs/038-use-macro-globals.pt
+src/chameleon/tests/inputs/038.xml
+src/chameleon/tests/inputs/039-globals.pt
+src/chameleon/tests/inputs/039.xml
+src/chameleon/tests/inputs/040-macro-using-template-symbol.pt
+src/chameleon/tests/inputs/040.xml
+src/chameleon/tests/inputs/041-translate-nested-names.pt
+src/chameleon/tests/inputs/041.xml
+src/chameleon/tests/inputs/042-use-macro-fill-footer.pt
+src/chameleon/tests/inputs/042.xml
+src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt
+src/chameleon/tests/inputs/043.xml
+src/chameleon/tests/inputs/044-tuple-define.pt
+src/chameleon/tests/inputs/044.xml
+src/chameleon/tests/inputs/045-namespaces.pt
+src/chameleon/tests/inputs/045.xml
+src/chameleon/tests/inputs/046-extend-macro.pt
+src/chameleon/tests/inputs/046.xml
+src/chameleon/tests/inputs/047-use-extended-macro.pt
+src/chameleon/tests/inputs/047.xml
+src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt
+src/chameleon/tests/inputs/048.xml
+src/chameleon/tests/inputs/049-entities-in-attributes.pt
+src/chameleon/tests/inputs/049.xml
+src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt
+src/chameleon/tests/inputs/050.xml
+src/chameleon/tests/inputs/051-use-non-extended-macro.pt
+src/chameleon/tests/inputs/051.xml
+src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt
+src/chameleon/tests/inputs/052.xml
+src/chameleon/tests/inputs/053-special-characters-in-attributes.pt
+src/chameleon/tests/inputs/053.xml
+src/chameleon/tests/inputs/054-import-expression.pt
+src/chameleon/tests/inputs/054.xml
+src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt
+src/chameleon/tests/inputs/055.xml
+src/chameleon/tests/inputs/056-comment-attribute.pt
+src/chameleon/tests/inputs/056.xml
+src/chameleon/tests/inputs/057-order.pt
+src/chameleon/tests/inputs/057.xml
+src/chameleon/tests/inputs/058-script.pt
+src/chameleon/tests/inputs/058.xml
+src/chameleon/tests/inputs/059-embedded-javascript.pt
+src/chameleon/tests/inputs/059.xml
+src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt
+src/chameleon/tests/inputs/060.xml
+src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt
+src/chameleon/tests/inputs/061.xml
+src/chameleon/tests/inputs/062-comments-and-expressions.pt
+src/chameleon/tests/inputs/062.xml
+src/chameleon/tests/inputs/063-continuation.pt
+src/chameleon/tests/inputs/063.xml
+src/chameleon/tests/inputs/064-tags-and-special-characters.pt
+src/chameleon/tests/inputs/064.xml
+src/chameleon/tests/inputs/065-use-macro-in-fill.pt
+src/chameleon/tests/inputs/065.xml
+src/chameleon/tests/inputs/066-load-expression.pt
+src/chameleon/tests/inputs/066.xml
+src/chameleon/tests/inputs/067-attribute-decode.pt
+src/chameleon/tests/inputs/067.xml
+src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt
+src/chameleon/tests/inputs/068.xml
+src/chameleon/tests/inputs/069-translation-domain-and-macro.pt
+src/chameleon/tests/inputs/069.xml
+src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt
+src/chameleon/tests/inputs/070.xml
+src/chameleon/tests/inputs/071-html-attribute-defaults.pt
+src/chameleon/tests/inputs/071.xml
+src/chameleon/tests/inputs/072-repeat-interpolation.pt
+src/chameleon/tests/inputs/072.xml
+src/chameleon/tests/inputs/073-utf8-encoded.pt
+src/chameleon/tests/inputs/073.xml
+src/chameleon/tests/inputs/074-encoded-template.pt
+src/chameleon/tests/inputs/074.xml
+src/chameleon/tests/inputs/075-nested-macros.pt
+src/chameleon/tests/inputs/075.xml
+src/chameleon/tests/inputs/076-nested-macro-override.pt
+src/chameleon/tests/inputs/076.xml
+src/chameleon/tests/inputs/077-i18n-attributes.pt
+src/chameleon/tests/inputs/077.xml
+src/chameleon/tests/inputs/078-tags-and-newlines.pt
+src/chameleon/tests/inputs/078.xml
+src/chameleon/tests/inputs/079-implicit-i18n.pt
+src/chameleon/tests/inputs/079.xml
+src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt
+src/chameleon/tests/inputs/080.xml
+src/chameleon/tests/inputs/081-load-spec.pt
+src/chameleon/tests/inputs/081.xml
+src/chameleon/tests/inputs/082-load-spec-computed.pt
+src/chameleon/tests/inputs/082.xml
+src/chameleon/tests/inputs/083-template-dict-to-macro.pt
+src/chameleon/tests/inputs/083.xml
+src/chameleon/tests/inputs/084-interpolation-in-cdata.pt
+src/chameleon/tests/inputs/084.xml
+src/chameleon/tests/inputs/085-nested-translation.pt
+src/chameleon/tests/inputs/085.xml
+src/chameleon/tests/inputs/086-self-closing.pt
+src/chameleon/tests/inputs/086.xml
+src/chameleon/tests/inputs/087-code-blocks.pt
+src/chameleon/tests/inputs/087.xml
+src/chameleon/tests/inputs/088-python-newlines.pt
+src/chameleon/tests/inputs/088.xml
+src/chameleon/tests/inputs/089.xml
+src/chameleon/tests/inputs/090.xml
+src/chameleon/tests/inputs/091.xml
+src/chameleon/tests/inputs/092.xml
+src/chameleon/tests/inputs/093.xml
+src/chameleon/tests/inputs/094.xml
+src/chameleon/tests/inputs/095.xml
+src/chameleon/tests/inputs/096.xml
+src/chameleon/tests/inputs/097.xml
+src/chameleon/tests/inputs/098.xml
+src/chameleon/tests/inputs/099.xml
+src/chameleon/tests/inputs/100.xml
+src/chameleon/tests/inputs/101-unclosed-tags.html
+src/chameleon/tests/inputs/101.xml
+src/chameleon/tests/inputs/102-unquoted-attributes.html
+src/chameleon/tests/inputs/102.xml
+src/chameleon/tests/inputs/103-simple-attribute.html
+src/chameleon/tests/inputs/103.xml
+src/chameleon/tests/inputs/104.xml
+src/chameleon/tests/inputs/105.xml
+src/chameleon/tests/inputs/106.xml
+src/chameleon/tests/inputs/107.xml
+src/chameleon/tests/inputs/108.xml
+src/chameleon/tests/inputs/109.xml
+src/chameleon/tests/inputs/110.xml
+src/chameleon/tests/inputs/111.xml
+src/chameleon/tests/inputs/112.xml
+src/chameleon/tests/inputs/113.xml
+src/chameleon/tests/inputs/114.xml
+src/chameleon/tests/inputs/115.xml
+src/chameleon/tests/inputs/116.xml
+src/chameleon/tests/inputs/117.xml
+src/chameleon/tests/inputs/118.xml
+src/chameleon/tests/inputs/119.xml
+src/chameleon/tests/inputs/greeting.pt
+src/chameleon/tests/inputs/hello_world.pt
+src/chameleon/tests/inputs/hello_world.txt
+src/chameleon/tests/outputs/001.html
+src/chameleon/tests/outputs/001.pt
+src/chameleon/tests/outputs/001.txt
+src/chameleon/tests/outputs/002.pt
+src/chameleon/tests/outputs/003.pt
+src/chameleon/tests/outputs/004.pt
+src/chameleon/tests/outputs/005.pt
+src/chameleon/tests/outputs/006.pt
+src/chameleon/tests/outputs/007.pt
+src/chameleon/tests/outputs/008.pt
+src/chameleon/tests/outputs/009.pt
+src/chameleon/tests/outputs/010.pt
+src/chameleon/tests/outputs/011-en.pt
+src/chameleon/tests/outputs/011.pt
+src/chameleon/tests/outputs/012-en.pt
+src/chameleon/tests/outputs/012.pt
+src/chameleon/tests/outputs/013.pt
+src/chameleon/tests/outputs/014.pt
+src/chameleon/tests/outputs/015-en.pt
+src/chameleon/tests/outputs/015.pt
+src/chameleon/tests/outputs/016-en.pt
+src/chameleon/tests/outputs/016.pt
+src/chameleon/tests/outputs/017.pt
+src/chameleon/tests/outputs/018-en.pt
+src/chameleon/tests/outputs/018.pt
+src/chameleon/tests/outputs/019.pt
+src/chameleon/tests/outputs/020.pt
+src/chameleon/tests/outputs/021-en.pt
+src/chameleon/tests/outputs/021.pt
+src/chameleon/tests/outputs/022.pt
+src/chameleon/tests/outputs/023.pt
+src/chameleon/tests/outputs/024.pt
+src/chameleon/tests/outputs/025.pt
+src/chameleon/tests/outputs/026.pt
+src/chameleon/tests/outputs/027.pt
+src/chameleon/tests/outputs/028.pt
+src/chameleon/tests/outputs/029.pt
+src/chameleon/tests/outputs/030.pt
+src/chameleon/tests/outputs/031.pt
+src/chameleon/tests/outputs/032.pt
+src/chameleon/tests/outputs/033.pt
+src/chameleon/tests/outputs/034.pt
+src/chameleon/tests/outputs/035.pt
+src/chameleon/tests/outputs/036.pt
+src/chameleon/tests/outputs/037.pt
+src/chameleon/tests/outputs/038.pt
+src/chameleon/tests/outputs/039.pt
+src/chameleon/tests/outputs/040.pt
+src/chameleon/tests/outputs/041.pt
+src/chameleon/tests/outputs/042.pt
+src/chameleon/tests/outputs/043.pt
+src/chameleon/tests/outputs/044.pt
+src/chameleon/tests/outputs/045.pt
+src/chameleon/tests/outputs/046.pt
+src/chameleon/tests/outputs/047.pt
+src/chameleon/tests/outputs/048.pt
+src/chameleon/tests/outputs/049.pt
+src/chameleon/tests/outputs/050.pt
+src/chameleon/tests/outputs/051.pt
+src/chameleon/tests/outputs/052.pt
+src/chameleon/tests/outputs/053.pt
+src/chameleon/tests/outputs/054.pt
+src/chameleon/tests/outputs/055.pt
+src/chameleon/tests/outputs/056.pt
+src/chameleon/tests/outputs/057.pt
+src/chameleon/tests/outputs/058.pt
+src/chameleon/tests/outputs/059.pt
+src/chameleon/tests/outputs/060.pt
+src/chameleon/tests/outputs/061.pt
+src/chameleon/tests/outputs/062.pt
+src/chameleon/tests/outputs/063.pt
+src/chameleon/tests/outputs/064.pt
+src/chameleon/tests/outputs/065.pt
+src/chameleon/tests/outputs/066.pt
+src/chameleon/tests/outputs/067.pt
+src/chameleon/tests/outputs/068.pt
+src/chameleon/tests/outputs/069-en.pt
+src/chameleon/tests/outputs/069.pt
+src/chameleon/tests/outputs/070-en.pt
+src/chameleon/tests/outputs/070.pt
+src/chameleon/tests/outputs/071.pt
+src/chameleon/tests/outputs/072.pt
+src/chameleon/tests/outputs/073.pt
+src/chameleon/tests/outputs/074.pt
+src/chameleon/tests/outputs/075.pt
+src/chameleon/tests/outputs/076.pt
+src/chameleon/tests/outputs/077-en.pt
+src/chameleon/tests/outputs/077.pt
+src/chameleon/tests/outputs/078.pt
+src/chameleon/tests/outputs/079-en.pt
+src/chameleon/tests/outputs/079.pt
+src/chameleon/tests/outputs/080.pt
+src/chameleon/tests/outputs/081.pt
+src/chameleon/tests/outputs/082.pt
+src/chameleon/tests/outputs/083.pt
+src/chameleon/tests/outputs/084.pt
+src/chameleon/tests/outputs/085-en.pt
+src/chameleon/tests/outputs/085.pt
+src/chameleon/tests/outputs/086.pt
+src/chameleon/tests/outputs/087.pt
+src/chameleon/tests/outputs/088.pt
+src/chameleon/tests/outputs/101.html
+src/chameleon/tests/outputs/102.html
+src/chameleon/tests/outputs/103.html
+src/chameleon/tests/outputs/greeting.pt
+src/chameleon/tests/outputs/hello_world.pt
+src/chameleon/tests/outputs/hello_world.txt
+src/chameleon/zpt/__init__.py
+src/chameleon/zpt/loader.py
+src/chameleon/zpt/program.py
+src/chameleon/zpt/template.py
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt
@@ -0,0 +1,1 @@
+
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe
@@ -0,0 +1,1 @@
+
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt
@@ -0,0 +1,1 @@
+chameleon
diff --git a/lib/Chameleon-2.9.2/src/chameleon/__init__.py b/lib/Chameleon-2.9.2/src/chameleon/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/__init__.py
@@ -0,0 +1,5 @@
+from .zpt.template import PageTemplate
+from .zpt.template import PageTemplateFile
+from .zpt.template import PageTextTemplate
+from .zpt.template import PageTextTemplateFile
+from .zpt.loader import TemplateLoader as PageTemplateLoader
diff --git a/lib/Chameleon-2.9.2/src/chameleon/ast24.py b/lib/Chameleon-2.9.2/src/chameleon/ast24.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/ast24.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 by Armin Ronacher.
+# License: Python License.
+#
+
+import _ast
+
+from _ast import *
+
+
+def fix_missing_locations(node):
+ """
+ When you compile a node tree with compile(), the compiler expects lineno and
+ col_offset attributes for every node that supports them. This is rather
+ tedious to fill in for generated nodes, so this helper adds these attributes
+ recursively where not already set, by setting them to the values of the
+ parent node. It works recursively starting at *node*.
+ """
+ def _fix(node, lineno, col_offset):
+ if 'lineno' in node._attributes:
+ if not hasattr(node, 'lineno'):
+ node.lineno = lineno
+ else:
+ lineno = node.lineno
+ if 'col_offset' in node._attributes:
+ if not hasattr(node, 'col_offset'):
+ node.col_offset = col_offset
+ else:
+ col_offset = node.col_offset
+ for child in iter_child_nodes(node):
+ _fix(child, lineno, col_offset)
+ _fix(node, 1, 0)
+ return node
+
+
+def iter_child_nodes(node):
+ """
+ Yield all direct child nodes of *node*, that is, all fields that are nodes
+ and all items of fields that are lists of nodes.
+ """
+ for name, field in iter_fields(node):
+ if isinstance(field, (AST, _ast.AST)):
+ yield field
+ elif isinstance(field, list):
+ for item in field:
+ if isinstance(item, (AST, _ast.AST)):
+ yield item
+
+
+def iter_fields(node):
+ """
+ Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
+ that is present on *node*.
+ """
+
+ for field in node._fields or ():
+ try:
+ yield field, getattr(node, field)
+ except AttributeError:
+ pass
+
+
+def walk(node):
+ """
+ Recursively yield all child nodes of *node*, in no specified order. This is
+ useful if you only want to modify nodes in place and don't care about the
+ context.
+ """
+ from collections import deque
+ todo = deque([node])
+ while todo:
+ node = todo.popleft()
+ todo.extend(iter_child_nodes(node))
+ yield node
+
+
+class NodeVisitor(object):
+ """
+ A node visitor base class that walks the abstract syntax tree and calls a
+ visitor function for every node found. This function may return a value
+ which is forwarded by the `visit` method.
+
+ This class is meant to be subclassed, with the subclass adding visitor
+ methods.
+
+ Per default the visitor functions for the nodes are ``'visit_'`` +
+ class name of the node. So a `TryFinally` node visit function would
+ be `visit_TryFinally`. This behavior can be changed by overriding
+ the `visit` method. If no visitor function exists for a node
+ (return value `None`) the `generic_visit` visitor is used instead.
+
+ Don't use the `NodeVisitor` if you want to apply changes to nodes during
+ traversing. For this a special visitor exists (`NodeTransformer`) that
+ allows modifications.
+ """
+
+ def visit(self, node):
+ """Visit a node."""
+ method = 'visit_' + node.__class__.__name__
+ visitor = getattr(self, method, self.generic_visit)
+ return visitor(node)
+
+ def generic_visit(self, node):
+ """Called if no explicit visitor function exists for a node."""
+ for field, value in iter_fields(node):
+ if isinstance(value, list):
+ for item in value:
+ if isinstance(item, (AST, _ast.AST)):
+ self.visit(item)
+ elif isinstance(value, (AST, _ast.AST)):
+ self.visit(value)
+
+
+class AST(object):
+ _fields = ()
+ _attributes = 'lineno', 'col_offset'
+
+ def __init__(self, *args, **kwargs):
+ self.__dict__.update(kwargs)
+ self._fields = self._fields or ()
+ for name, value in zip(self._fields, args):
+ setattr(self, name, value)
+
+
+for name, cls in _ast.__dict__.items():
+ if isinstance(cls, type) and issubclass(cls, _ast.AST):
+ try:
+ cls.__bases__ = (AST, ) + cls.__bases__
+ except TypeError:
+ pass
+
+
+class ExceptHandler(AST):
+ _fields = "type", "name", "body"
diff --git a/lib/Chameleon-2.9.2/src/chameleon/astutil.py b/lib/Chameleon-2.9.2/src/chameleon/astutil.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/astutil.py
@@ -0,0 +1,926 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+"""Support classes for generating code from abstract syntax trees."""
+
+try:
+ import ast
+except ImportError:
+ from chameleon import ast24 as ast
+
+import sys
+import logging
+import weakref
+
+node_annotations = weakref.WeakKeyDictionary()
+
+try:
+ node_annotations[ast.Name()] = None
+except TypeError:
+ logging.debug(
+ "Unable to create weak references to AST nodes. " \
+ "A lock will be used around compilation loop."
+ )
+
+ node_annotations = {}
+
+__docformat__ = 'restructuredtext en'
+
+
+def annotated(value):
+ node = load("annotation")
+ node_annotations[node] = value
+ return node
+
+
+def parse(source, mode='eval'):
+ return compile(source, '', mode, ast.PyCF_ONLY_AST)
+
+
+def load(name):
+ return ast.Name(id=name, ctx=ast.Load())
+
+
+def store(name):
+ return ast.Name(id=name, ctx=ast.Store())
+
+
+def param(name):
+ return ast.Name(id=name, ctx=ast.Param())
+
+
+def delete(name):
+ return ast.Name(id=name, ctx=ast.Del())
+
+
+def subscript(name, value, ctx):
+ return ast.Subscript(
+ value=value,
+ slice=ast.Index(value=ast.Str(s=name)),
+ ctx=ctx,
+ )
+
+
+def walk_names(target, mode):
+ for node in ast.walk(target):
+ if isinstance(node, ast.Name) and \
+ isinstance(node.ctx, mode):
+ yield node.id
+
+
+def copy(source, target):
+ target.__class__ = source.__class__
+ target.__dict__ = source.__dict__
+
+
+def swap(root, replacement, name):
+ for node in ast.walk(root):
+ if (isinstance(node, ast.Name) and
+ isinstance(node.ctx, ast.Load) and
+ node.id == name):
+ assert hasattr(replacement, '_fields')
+ node_annotations.setdefault(node, replacement)
+
+
+def marker(name):
+ return ast.Str(s="__%s" % name)
+
+
+class Node(object):
+ """AST baseclass that gives us a convenient initialization
+ method. We explicitly declare and use the ``_fields`` attribute."""
+
+ _fields = ()
+
+ def __init__(self, *args, **kwargs):
+ assert isinstance(self._fields, tuple)
+ self.__dict__.update(kwargs)
+ for name, value in zip(self._fields, args):
+ setattr(self, name, value)
+
+ def __repr__(self):
+ """Poor man's single-line pretty printer."""
+
+ name = type(self).__name__
+ return '<%s%s at %x>' % (
+ name,
+ "".join(" %s=%r" % (name, getattr(self, name, "\"?\""))
+ for name in self._fields),
+ id(self)
+ )
+
+
+class Builtin(Node):
+ """Represents a Python builtin.
+
+ Used when a builtin is used internally by the compiler, to avoid
+ clashing with a user assignment (e.g. ``help`` is a builtin, but
+ also commonly assigned in templates).
+ """
+
+ _fields = "id", "ctx"
+
+ ctx = ast.Load()
+
+
+class Symbol(Node):
+ """Represents an importable symbol."""
+
+ _fields = "value",
+
+
+class Static(Node):
+ """Represents a static value."""
+
+ _fields = "value", "name"
+
+ name = None
+
+
+class Comment(Node):
+ _fields = "text", "space", "stmt"
+
+ stmt = None
+ space = ""
+
+
+class ASTCodeGenerator(object):
+ """General purpose base class for AST transformations.
+
+ Every visitor method can be overridden to return an AST node that has been
+ altered or replaced in some way.
+ """
+
+ def __init__(self, tree):
+ self.lines_info = []
+ self.line_info = []
+ self.lines = []
+ self.line = ""
+ self.last = None
+ self.indent = 0
+ self.blame_stack = []
+ self.visit(tree)
+
+ if self.line.strip():
+ self._new_line()
+
+ self.line = None
+ self.line_info = None
+
+ # strip trivial lines
+ self.code = "\n".join(
+ line.strip() and line or ""
+ for line in self.lines
+ )
+
+ def _change_indent(self, delta):
+ self.indent += delta
+
+ def _new_line(self):
+ if self.line is not None:
+ self.lines.append(self.line)
+ self.lines_info.append(self.line_info)
+ self.line = ' ' * 4 * self.indent
+ if len(self.blame_stack) == 0:
+ self.line_info = []
+ self.last = None
+ else:
+ self.line_info = [(0, self.blame_stack[-1],)]
+ self.last = self.blame_stack[-1]
+
+ def _write(self, s):
+ if len(s) == 0:
+ return
+ if len(self.blame_stack) == 0:
+ if self.last is not None:
+ self.last = None
+ self.line_info.append((len(self.line), self.last))
+ else:
+ if self.last != self.blame_stack[-1]:
+ self.last = self.blame_stack[-1]
+ self.line_info.append((len(self.line), self.last))
+ self.line += s
+
+ def flush(self):
+ if self.line:
+ self._new_line()
+
+ def visit(self, node):
+ if node is None:
+ return None
+ if type(node) is tuple:
+ return tuple([self.visit(n) for n in node])
+ try:
+ self.blame_stack.append((node.lineno, node.col_offset,))
+ info = True
+ except AttributeError:
+ info = False
+ visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None)
+ if visitor is None:
+ raise Exception('No handler for ``%s`` (%s).' % (
+ node.__class__.__name__, repr(node)))
+ ret = visitor(node)
+ if info:
+ self.blame_stack.pop()
+ return ret
+
+ def visit_Module(self, node):
+ for n in node.body:
+ self.visit(n)
+ visit_Interactive = visit_Module
+ visit_Suite = visit_Module
+
+ def visit_Expression(self, node):
+ return self.visit(node.body)
+
+ # arguments = (expr* args, identifier? vararg,
+ # identifier? kwarg, expr* defaults)
+ def visit_arguments(self, node):
+ first = True
+ no_default_count = len(node.args) - len(node.defaults)
+ for i, arg in enumerate(node.args):
+ if not first:
+ self._write(', ')
+ else:
+ first = False
+ self.visit(arg)
+ if i >= no_default_count:
+ self._write('=')
+ self.visit(node.defaults[i - no_default_count])
+ if getattr(node, 'vararg', None):
+ if not first:
+ self._write(', ')
+ else:
+ first = False
+ self._write('*' + node.vararg)
+ if getattr(node, 'kwarg', None):
+ if not first:
+ self._write(', ')
+ else:
+ first = False
+ self._write('**' + node.kwarg)
+
+ def visit_arg(self, node):
+ self._write(node.arg)
+
+ # FunctionDef(identifier name, arguments args,
+ # stmt* body, expr* decorators)
+ def visit_FunctionDef(self, node):
+ self._new_line()
+ for decorator in getattr(node, 'decorator_list', ()):
+ self._new_line()
+ self._write('@')
+ self.visit(decorator)
+ self._new_line()
+ self._write('def ' + node.name + '(')
+ self.visit(node.args)
+ self._write('):')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # ClassDef(identifier name, expr* bases, stmt* body)
+ def visit_ClassDef(self, node):
+ self._new_line()
+ self._write('class ' + node.name)
+ if node.bases:
+ self._write('(')
+ self.visit(node.bases[0])
+ for base in node.bases[1:]:
+ self._write(', ')
+ self.visit(base)
+ self._write(')')
+ self._write(':')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # Return(expr? value)
+ def visit_Return(self, node):
+ self._new_line()
+ self._write('return')
+ if getattr(node, 'value', None):
+ self._write(' ')
+ self.visit(node.value)
+
+ # Delete(expr* targets)
+ def visit_Delete(self, node):
+ self._new_line()
+ self._write('del ')
+ self.visit(node.targets[0])
+ for target in node.targets[1:]:
+ self._write(', ')
+ self.visit(target)
+
+ # Assign(expr* targets, expr value)
+ def visit_Assign(self, node):
+ self._new_line()
+ for target in node.targets:
+ self.visit(target)
+ self._write(' = ')
+ self.visit(node.value)
+
+ # AugAssign(expr target, operator op, expr value)
+ def visit_AugAssign(self, node):
+ self._new_line()
+ self.visit(node.target)
+ self._write(' ' + self.binary_operators[node.op.__class__] + '= ')
+ self.visit(node.value)
+
+ # Print(expr? dest, expr* values, bool nl)
+ def visit_Print(self, node):
+ self._new_line()
+ self._write('print')
+ if getattr(node, 'dest', None):
+ self._write(' >> ')
+ self.visit(node.dest)
+ if getattr(node, 'values', None):
+ self._write(', ')
+ else:
+ self._write(' ')
+ if getattr(node, 'values', None):
+ self.visit(node.values[0])
+ for value in node.values[1:]:
+ self._write(', ')
+ self.visit(value)
+ if not node.nl:
+ self._write(',')
+
+ # For(expr target, expr iter, stmt* body, stmt* orelse)
+ def visit_For(self, node):
+ self._new_line()
+ self._write('for ')
+ self.visit(node.target)
+ self._write(' in ')
+ self.visit(node.iter)
+ self._write(':')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+ if getattr(node, 'orelse', None):
+ self._new_line()
+ self._write('else:')
+ self._change_indent(1)
+ for statement in node.orelse:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # While(expr test, stmt* body, stmt* orelse)
+ def visit_While(self, node):
+ self._new_line()
+ self._write('while ')
+ self.visit(node.test)
+ self._write(':')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+ if getattr(node, 'orelse', None):
+ self._new_line()
+ self._write('else:')
+ self._change_indent(1)
+ for statement in node.orelse:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # If(expr test, stmt* body, stmt* orelse)
+ def visit_If(self, node):
+ self._new_line()
+ self._write('if ')
+ self.visit(node.test)
+ self._write(':')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+ if getattr(node, 'orelse', None):
+ self._new_line()
+ self._write('else:')
+ self._change_indent(1)
+ for statement in node.orelse:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # With(expr context_expr, expr? optional_vars, stmt* body)
+ def visit_With(self, node):
+ self._new_line()
+ self._write('with ')
+ self.visit(node.context_expr)
+ if getattr(node, 'optional_vars', None):
+ self._write(' as ')
+ self.visit(node.optional_vars)
+ self._write(':')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # Raise(expr? type, expr? inst, expr? tback)
+ def visit_Raise(self, node):
+ self._new_line()
+ self._write('raise')
+ if not getattr(node, "type", None):
+ exc = getattr(node, "exc", None)
+ if exc is None:
+ return
+ self._write(' ')
+ return self.visit(exc)
+ self._write(' ')
+ self.visit(node.type)
+ if not node.inst:
+ return
+ self._write(', ')
+ self.visit(node.inst)
+ if not node.tback:
+ return
+ self._write(', ')
+ self.visit(node.tback)
+
+ # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
+ def visit_Try(self, node):
+ self._new_line()
+ self._write('try:')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+ if getattr(node, 'handlers', None):
+ for handler in node.handlers:
+ self.visit(handler)
+ self._new_line()
+
+ if getattr(node, 'orelse', None):
+ self._write('else:')
+ self._change_indent(1)
+ for statement in node.orelse:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ if getattr(node, 'finalbody', None):
+ self._new_line()
+ self._write('finally:')
+ self._change_indent(1)
+ for statement in node.finalbody:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
+ def visit_TryExcept(self, node):
+ self._new_line()
+ self._write('try:')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+ if getattr(node, 'handlers', None):
+ for handler in node.handlers:
+ self.visit(handler)
+ self._new_line()
+ if getattr(node, 'orelse', None):
+ self._write('else:')
+ self._change_indent(1)
+ for statement in node.orelse:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # excepthandler = (expr? type, expr? name, stmt* body)
+ def visit_ExceptHandler(self, node):
+ self._new_line()
+ self._write('except')
+ if getattr(node, 'type', None):
+ self._write(' ')
+ self.visit(node.type)
+ if getattr(node, 'name', None):
+ if sys.version_info[0] == 2:
+ assert getattr(node, 'type', None)
+ self._write(', ')
+ else:
+ self._write(' as ')
+ self.visit(node.name)
+ self._write(':')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+ visit_excepthandler = visit_ExceptHandler
+
+ # TryFinally(stmt* body, stmt* finalbody)
+ def visit_TryFinally(self, node):
+ self._new_line()
+ self._write('try:')
+ self._change_indent(1)
+ for statement in node.body:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ if getattr(node, 'finalbody', None):
+ self._new_line()
+ self._write('finally:')
+ self._change_indent(1)
+ for statement in node.finalbody:
+ self.visit(statement)
+ self._change_indent(-1)
+
+ # Assert(expr test, expr? msg)
+ def visit_Assert(self, node):
+ self._new_line()
+ self._write('assert ')
+ self.visit(node.test)
+ if getattr(node, 'msg', None):
+ self._write(', ')
+ self.visit(node.msg)
+
+ def visit_alias(self, node):
+ self._write(node.name)
+ if getattr(node, 'asname', None):
+ self._write(' as ')
+ self._write(node.asname)
+
+ # Import(alias* names)
+ def visit_Import(self, node):
+ self._new_line()
+ self._write('import ')
+ self.visit(node.names[0])
+ for name in node.names[1:]:
+ self._write(', ')
+ self.visit(name)
+
+ # ImportFrom(identifier module, alias* names, int? level)
+ def visit_ImportFrom(self, node):
+ self._new_line()
+ self._write('from ')
+ if node.level:
+ self._write('.' * node.level)
+ self._write(node.module)
+ self._write(' import ')
+ self.visit(node.names[0])
+ for name in node.names[1:]:
+ self._write(', ')
+ self.visit(name)
+
+ # Exec(expr body, expr? globals, expr? locals)
+ def visit_Exec(self, node):
+ self._new_line()
+ self._write('exec ')
+ self.visit(node.body)
+ if not node.globals:
+ return
+ self._write(', ')
+ self.visit(node.globals)
+ if not node.locals:
+ return
+ self._write(', ')
+ self.visit(node.locals)
+
+ # Global(identifier* names)
+ def visit_Global(self, node):
+ self._new_line()
+ self._write('global ')
+ self.visit(node.names[0])
+ for name in node.names[1:]:
+ self._write(', ')
+ self.visit(name)
+
+ # Expr(expr value)
+ def visit_Expr(self, node):
+ self._new_line()
+ self.visit(node.value)
+
+ # Pass
+ def visit_Pass(self, node):
+ self._new_line()
+ self._write('pass')
+
+ # Break
+ def visit_Break(self, node):
+ self._new_line()
+ self._write('break')
+
+ # Continue
+ def visit_Continue(self, node):
+ self._new_line()
+ self._write('continue')
+
+ ### EXPRESSIONS
+ def with_parens(f):
+ def _f(self, node):
+ self._write('(')
+ f(self, node)
+ self._write(')')
+ return _f
+
+ bool_operators = {ast.And: 'and', ast.Or: 'or'}
+
+ # BoolOp(boolop op, expr* values)
+ @with_parens
+ def visit_BoolOp(self, node):
+ joiner = ' ' + self.bool_operators[node.op.__class__] + ' '
+ self.visit(node.values[0])
+ for value in node.values[1:]:
+ self._write(joiner)
+ self.visit(value)
+
+ binary_operators = {
+ ast.Add: '+',
+ ast.Sub: '-',
+ ast.Mult: '*',
+ ast.Div: '/',
+ ast.Mod: '%',
+ ast.Pow: '**',
+ ast.LShift: '<<',
+ ast.RShift: '>>',
+ ast.BitOr: '|',
+ ast.BitXor: '^',
+ ast.BitAnd: '&',
+ ast.FloorDiv: '//'
+ }
+
+ # BinOp(expr left, operator op, expr right)
+ @with_parens
+ def visit_BinOp(self, node):
+ self.visit(node.left)
+ self._write(' ' + self.binary_operators[node.op.__class__] + ' ')
+ self.visit(node.right)
+
+ unary_operators = {
+ ast.Invert: '~',
+ ast.Not: 'not',
+ ast.UAdd: '+',
+ ast.USub: '-',
+ }
+
+ # UnaryOp(unaryop op, expr operand)
+ def visit_UnaryOp(self, node):
+ self._write(self.unary_operators[node.op.__class__] + ' ')
+ self.visit(node.operand)
+
+ # Lambda(arguments args, expr body)
+ @with_parens
+ def visit_Lambda(self, node):
+ self._write('lambda ')
+ self.visit(node.args)
+ self._write(': ')
+ self.visit(node.body)
+
+ # IfExp(expr test, expr body, expr orelse)
+ @with_parens
+ def visit_IfExp(self, node):
+ self.visit(node.body)
+ self._write(' if ')
+ self.visit(node.test)
+ self._write(' else ')
+ self.visit(node.orelse)
+
+ # Dict(expr* keys, expr* values)
+ def visit_Dict(self, node):
+ self._write('{')
+ for key, value in zip(node.keys, node.values):
+ self.visit(key)
+ self._write(': ')
+ self.visit(value)
+ self._write(', ')
+ self._write('}')
+
+ def visit_Set(self, node):
+ self._write('{')
+ elts = list(node.elts)
+ last = elts.pop()
+ for elt in elts:
+ self.visit(elt)
+ self._write(', ')
+ self.visit(last)
+ self._write('}')
+
+ # ListComp(expr elt, comprehension* generators)
+ def visit_ListComp(self, node):
+ self._write('[')
+ self.visit(node.elt)
+ for generator in node.generators:
+ # comprehension = (expr target, expr iter, expr* ifs)
+ self._write(' for ')
+ self.visit(generator.target)
+ self._write(' in ')
+ self.visit(generator.iter)
+ for ifexpr in generator.ifs:
+ self._write(' if ')
+ self.visit(ifexpr)
+ self._write(']')
+
+ # GeneratorExp(expr elt, comprehension* generators)
+ def visit_GeneratorExp(self, node):
+ self._write('(')
+ self.visit(node.elt)
+ for generator in node.generators:
+ # comprehension = (expr target, expr iter, expr* ifs)
+ self._write(' for ')
+ self.visit(generator.target)
+ self._write(' in ')
+ self.visit(generator.iter)
+ for ifexpr in generator.ifs:
+ self._write(' if ')
+ self.visit(ifexpr)
+ self._write(')')
+
+ # Yield(expr? value)
+ def visit_Yield(self, node):
+ self._write('yield')
+ if getattr(node, 'value', None):
+ self._write(' ')
+ self.visit(node.value)
+
+ comparison_operators = {
+ ast.Eq: '==',
+ ast.NotEq: '!=',
+ ast.Lt: '<',
+ ast.LtE: '<=',
+ ast.Gt: '>',
+ ast.GtE: '>=',
+ ast.Is: 'is',
+ ast.IsNot: 'is not',
+ ast.In: 'in',
+ ast.NotIn: 'not in',
+ }
+
+ # Compare(expr left, cmpop* ops, expr* comparators)
+ @with_parens
+ def visit_Compare(self, node):
+ self.visit(node.left)
+ for op, comparator in zip(node.ops, node.comparators):
+ self._write(' ' + self.comparison_operators[op.__class__] + ' ')
+ self.visit(comparator)
+
+ # Call(expr func, expr* args, keyword* keywords,
+ # expr? starargs, expr? kwargs)
+ def visit_Call(self, node):
+ self.visit(node.func)
+ self._write('(')
+ first = True
+ for arg in node.args:
+ if not first:
+ self._write(', ')
+ first = False
+ self.visit(arg)
+
+ for keyword in node.keywords:
+ if not first:
+ self._write(', ')
+ first = False
+ # keyword = (identifier arg, expr value)
+ self._write(keyword.arg)
+ self._write('=')
+ self.visit(keyword.value)
+ if getattr(node, 'starargs', None):
+ if not first:
+ self._write(', ')
+ first = False
+ self._write('*')
+ self.visit(node.starargs)
+
+ if getattr(node, 'kwargs', None):
+ if not first:
+ self._write(', ')
+ first = False
+ self._write('**')
+ self.visit(node.kwargs)
+ self._write(')')
+
+ # Repr(expr value)
+ def visit_Repr(self, node):
+ self._write('`')
+ self.visit(node.value)
+ self._write('`')
+
+ # Num(object n)
+ def visit_Num(self, node):
+ self._write(repr(node.n))
+
+ # Str(string s)
+ def visit_Str(self, node):
+ self._write(repr(node.s))
+
+ # Attribute(expr value, identifier attr, expr_context ctx)
+ def visit_Attribute(self, node):
+ self.visit(node.value)
+ self._write('.')
+ self._write(node.attr)
+
+ # Subscript(expr value, slice slice, expr_context ctx)
+ def visit_Subscript(self, node):
+ self.visit(node.value)
+ self._write('[')
+
+ def _process_slice(node):
+ if isinstance(node, ast.Ellipsis):
+ self._write('...')
+ elif isinstance(node, ast.Slice):
+ if getattr(node, 'lower', 'None'):
+ self.visit(node.lower)
+ self._write(':')
+ if getattr(node, 'upper', None):
+ self.visit(node.upper)
+ if getattr(node, 'step', None):
+ self._write(':')
+ self.visit(node.step)
+ elif isinstance(node, ast.Index):
+ self.visit(node.value)
+ elif isinstance(node, ast.ExtSlice):
+ self.visit(node.dims[0])
+ for dim in node.dims[1:]:
+ self._write(', ')
+ self.visit(dim)
+ else:
+ raise NotImplemented('Slice type not implemented')
+ _process_slice(node.slice)
+ self._write(']')
+
+ # Name(identifier id, expr_context ctx)
+ def visit_Name(self, node):
+ self._write(node.id)
+
+ # List(expr* elts, expr_context ctx)
+ def visit_List(self, node):
+ self._write('[')
+ for elt in node.elts:
+ self.visit(elt)
+ self._write(', ')
+ self._write(']')
+
+ # Tuple(expr *elts, expr_context ctx)
+ def visit_Tuple(self, node):
+ self._write('(')
+ for elt in node.elts:
+ self.visit(elt)
+ self._write(', ')
+ self._write(')')
+
+
+class AnnotationAwareVisitor(ast.NodeVisitor):
+ def visit(self, node):
+ annotation = node_annotations.get(node)
+ if annotation is not None:
+ assert hasattr(annotation, '_fields')
+ node = annotation
+
+ super(AnnotationAwareVisitor, self).visit(node)
+
+ def apply_transform(self, node):
+ if node not in node_annotations:
+ result = self.transform(node)
+ if result is not None and result is not node:
+ node_annotations[node] = result
+
+
+class NameLookupRewriteVisitor(AnnotationAwareVisitor):
+ def __init__(self, transform):
+ self.transform = transform
+ self.transformed = set()
+ self.scopes = [set()]
+
+ def __call__(self, node):
+ self.visit(node)
+ return self.transformed
+
+ def visit_Name(self, node):
+ scope = self.scopes[-1]
+ if isinstance(node.ctx, ast.Param):
+ scope.add(node.id)
+ elif node.id not in scope:
+ self.transformed.add(node.id)
+ self.apply_transform(node)
+
+ def visit_FunctionDef(self, node):
+ self.scopes[-1].add(node.name)
+
+ def visit_alias(self, node):
+ name = node.asname if node.asname is not None else node.name
+ self.scopes[-1].add(name)
+
+ def visit_Lambda(self, node):
+ self.scopes.append(set())
+ try:
+ self.visit(node.args)
+ self.visit(node.body)
+ finally:
+ self.scopes.pop()
+
+
+class ItemLookupOnAttributeErrorVisitor(AnnotationAwareVisitor):
+ def __init__(self, transform):
+ self.transform = transform
+
+ def visit_Attribute(self, node):
+ self.generic_visit(node)
+ self.apply_transform(node)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/benchmark.py b/lib/Chameleon-2.9.2/src/chameleon/benchmark.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/benchmark.py
@@ -0,0 +1,478 @@
+import unittest
+import time
+import os
+import re
+from .utils import text_
+
+re_amp = re.compile(r'&(?!([A-Za-z]+|#[0-9]+);)')
+
+BIGTABLE_ZPT = """\
+<table xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<tr tal:repeat="row python: options['table']">
+<td tal:repeat="c python: row.values()">
+<span tal:define="d python: c + 1"
+tal:attributes="class python: 'column-' + str(d)"
+tal:content="python: d" />
+</td>
+</tr>
+</table>"""
+
+MANY_STRINGS_ZPT = """\
+<table xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<tr tal:repeat="i python: xrange(1000)">
+<td tal:content="string: number ${i}" />
+</tr>
+</table>
+"""
+
+HELLO_WORLD_ZPT = """\
+<html xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<body>
+<h1>Hello, world!</h1>
+</body>
+</html>
+"""
+
+I18N_ZPT = """\
+<html xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal"
+xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <body>
+ <div tal:repeat="i python: xrange(10)">
+ <div i18n:translate="">
+ Hello world!
+ </div>
+ <div i18n:translate="hello_world">
+ Hello world!
+ </div>
+ <div i18n:translate="">
+ <sup>Hello world!</sup>
+ </div>
+ </div>
+ </body>
+</html>
+"""
+
+
+def benchmark(title):
+ def decorator(f):
+ def wrapper(*args):
+ print(
+ "==========================\n " \
+ "%s\n==========================" % \
+ title)
+ return f(*args)
+ return wrapper
+ return decorator
+
+
+def timing(func, *args, **kwargs):
+ t1 = t2 = time.time()
+ i = 0
+ while t2 - t1 < 3:
+ func(**kwargs)
+ func(**kwargs)
+ func(**kwargs)
+ func(**kwargs)
+ i += 4
+ t2 = time.time()
+ return float(10 * (t2 - t1)) / i
+
+
+START = 0
+END = 1
+TAG = 2
+
+
+def yield_tokens(table=None):
+ index = []
+ tag = index.append
+ _re_amp = re_amp
+ tag(START)
+ yield "<", "html", "", ">\n"
+ for r in table:
+ tag(START)
+ yield "<", "tr", "", ">\n"
+
+ for c in r.values():
+ d = c + 1
+ tag(START)
+ yield "<", "td", "", ">\n"
+
+ _tmp5 = d
+ if not isinstance(_tmp5, unicode):
+ _tmp5 = str(_tmp5)
+ if ('&' in _tmp5):
+ if (';' in _tmp5):
+ _tmp5 = _re_amp.sub('&', _tmp5)
+ else:
+ _tmp5 = _tmp5.replace('&', '&')
+ if ('<' in _tmp5):
+ _tmp5 = _tmp5.replace('<', '<')
+ if ('>' in _tmp5):
+ _tmp5 = _tmp5.replace('>', '>')
+ if ('"' in _tmp5):
+ _tmp5 = _tmp5.replace('"', '"')
+ _tmp5 = "column-%s" % _tmp5
+
+ _tmp = d
+ if (_tmp.__class__ not in (str, unicode, int, float, )):
+ raise
+ if (_tmp is not None):
+ if not isinstance(_tmp, unicode):
+ _tmp = str(_tmp)
+ if ('&' in _tmp):
+ if (';' in _tmp):
+ _tmp = _re_amp.sub('&', _tmp)
+ else:
+ _tmp = _tmp.replace('&', '&')
+ if ('<' in _tmp):
+ _tmp = _tmp.replace('<', '<')
+ if ('>' in _tmp):
+ _tmp = _tmp.replace('>', '>')
+ tag(START)
+
+ t = ["classicism"]
+
+ yield "<", "span", " ", t[0], '="', _tmp5, '"', ">\n"
+ tag(END)
+ yield "</", "span", ">\n"
+ tag(END)
+ yield "</", "td", ">\n"
+ tag(END)
+ yield "</", "tr", ">\n"
+ tag(END)
+ yield "</", "html", ">\n"
+
+
+def yield_tokens_dict_version(**kwargs):
+ index = []
+ tag = index.append
+ _re_amp = re_amp
+ tag(START)
+ yield "<", "html", "", ">\n"
+
+ for r in kwargs['table']:
+ kwargs['r'] = r
+ tag(START)
+ yield "<", "tr", "", ">\n"
+
+ for c in kwargs['r'].values():
+ kwargs['d'] = c + 1
+ tag(START)
+ yield "<", "td", "", ">\n"
+
+ _tmp5 = kwargs['d']
+ if not isinstance(_tmp5, unicode):
+ _tmp5 = str(_tmp5)
+ if ('&' in _tmp5):
+ if (';' in _tmp5):
+ _tmp5 = _re_amp.sub('&', _tmp5)
+ else:
+ _tmp5 = _tmp5.replace('&', '&')
+ if ('<' in _tmp5):
+ _tmp5 = _tmp5.replace('<', '<')
+ if ('>' in _tmp5):
+ _tmp5 = _tmp5.replace('>', '>')
+ if ('"' in _tmp5):
+ _tmp5 = _tmp5.replace('"', '"')
+ _tmp5 = "column-%s" % _tmp5
+
+ _tmp = kwargs['d']
+ if (_tmp.__class__ not in (str, unicode, int, float, )):
+ raise
+ if (_tmp is not None):
+ if not isinstance(_tmp, unicode):
+ _tmp = str(_tmp)
+ if ('&' in _tmp):
+ if (';' in _tmp):
+ _tmp = _re_amp.sub('&', _tmp)
+ else:
+ _tmp = _tmp.replace('&', '&')
+ if ('<' in _tmp):
+ _tmp = _tmp.replace('<', '<')
+ if ('>' in _tmp):
+ _tmp = _tmp.replace('>', '>')
+ tag(START)
+
+ t = ["classicism"]
+
+ yield "<", "span", " ", t[0], '="', _tmp5, '"', ">\n"
+ tag(END)
+ yield "</", "span", ">\n"
+ tag(END)
+ yield "</", "td", ">\n"
+ tag(END)
+ yield "</", "tr", ">\n"
+ tag(END)
+ yield "</", "html", ">\n"
+
+
+def yield_stream(table=None):
+ _re_amp = re_amp
+ yield START, ("html", "", "\n"), None
+ for r in table:
+ yield START, ("tr", "", "\n"), None
+
+ for c in r.values():
+ d = c + 1
+ yield START, ("td", "", "\n"), None
+
+ _tmp5 = d
+ if not isinstance(_tmp5, unicode):
+ _tmp5 = str(_tmp5)
+ if ('&' in _tmp5):
+ if (';' in _tmp5):
+ _tmp5 = _re_amp.sub('&', _tmp5)
+ else:
+ _tmp5 = _tmp5.replace('&', '&')
+ if ('<' in _tmp5):
+ _tmp5 = _tmp5.replace('<', '<')
+ if ('>' in _tmp5):
+ _tmp5 = _tmp5.replace('>', '>')
+ if ('"' in _tmp5):
+ _tmp5 = _tmp5.replace('"', '"')
+ _tmp5 = "column-%s" % _tmp5
+
+ _tmp = d
+ if (_tmp.__class__ not in (str, unicode, int, float, )):
+ raise
+ if (_tmp is not None):
+ if not isinstance(_tmp, unicode):
+ _tmp = str(_tmp)
+ if ('&' in _tmp):
+ if (';' in _tmp):
+ _tmp = _re_amp.sub('&', _tmp)
+ else:
+ _tmp = _tmp.replace('&', '&')
+ if ('<' in _tmp):
+ _tmp = _tmp.replace('<', '<')
+ if ('>' in _tmp):
+ _tmp = _tmp.replace('>', '>')
+ yield START, ("span", "", _tmp, " ", "class", _tmp5), None
+
+ yield END, ("span", "", "\n"), None
+ yield END, ("td", "", "\n"), None
+ yield END, ("tr", "", "\n"), None
+ yield END, ("html", "", "\n"), None
+
+from itertools import chain
+
+
+def bigtable_python_tokens(table=None, renderer=None):
+ iterable = renderer(table=table)
+ stream = chain(*iterable)
+ return "".join(stream)
+
+
+def bigtable_python_stream(table=None, renderer=None):
+ stream = renderer(table=table)
+ return "".join(stream_output(stream))
+
+
+def bigtable_python_stream_with_filter(table=None, renderer=None):
+ stream = renderer(table=table)
+ return "".join(stream_output(uppercase_filter(stream)))
+
+
+def uppercase_filter(stream):
+ for kind, data, pos in stream:
+ if kind is START:
+ data = (data[0], data[1], data[2].upper(),) + data[3:]
+ elif kind is END:
+ data = (data[0], data[1], data[2].upper())
+ elif kind is TAG:
+ raise NotImplemented
+ yield kind, data, pos
+
+
+def stream_output(stream):
+ for kind, data, pos in stream:
+ if kind is START:
+ tag = data[0]
+ yield "<%s" % tag
+ l = len(data)
+
+ # optimize for common cases
+ if l == 3:
+ pass
+ elif l == 6:
+ yield '%s%s="%s"' % (data[3], data[4], data[5])
+ else:
+ i = 3
+ while i < l:
+ yield '%s%s="%s"' % (data[i], data[i + 1], data[i + 2])
+ i += 3
+ yield "%s>%s" % (data[1], data[2])
+ elif kind is END:
+ yield "</%s%s>%s" % data
+ elif kind is TAG:
+ raise NotImplemented
+
+
+class Benchmarks(unittest.TestCase):
+ 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)]
+
+ def setUp(self):
+ # set up i18n component
+ from zope.i18n import translate
+ from zope.i18n.interfaces import INegotiator
+ from zope.i18n.interfaces import ITranslationDomain
+ from zope.i18n.negotiator import Negotiator
+ from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+ from zope.i18n.tests.test_negotiator import Env
+ from zope.tales.tales import Context
+
+ self.env = Env(('klingon', 'da', 'en', 'fr', 'no'))
+
+ class ZopeI18NContext(Context):
+
+ def translate(self, msgid, domain=None, context=None,
+ mapping=None, default=None):
+ context = self.vars['options']['env']
+ return translate(msgid, domain, mapping,
+ context=context, default=default)
+
+ def _getContext(self, contexts=None, **kwcontexts):
+ if contexts is not None:
+ if kwcontexts:
+ kwcontexts.update(contexts)
+ else:
+ kwcontexts = contexts
+ return ZopeI18NContext(self, kwcontexts)
+
+ def _pt_getEngineContext(namespace):
+ self = namespace['template']
+ engine = self.pt_getEngine()
+ return _getContext(engine, namespace)
+
+ import zope.component
+ zope.component.provideUtility(Negotiator(), INegotiator)
+ catalog = SimpleTranslationDomain('domain')
+ zope.component.provideUtility(catalog, ITranslationDomain, 'domain')
+ self.files = os.path.abspath(os.path.join(__file__, '..', 'input'))
+
+ @staticmethod
+ def _chameleon(body, **kwargs):
+ from .zpt.template import PageTemplate
+ return PageTemplate(body, **kwargs)
+
+ @staticmethod
+ def _zope(body):
+ from zope.pagetemplate.pagetemplatefile import PageTemplate
+ template = PageTemplate()
+ template.pt_edit(body, 'text/xhtml')
+ return template
+
+ @benchmark(text_("BIGTABLE [python]"))
+ def test_bigtable(self):
+ options = {'table': self.table}
+
+ t_chameleon = timing(self._chameleon(BIGTABLE_ZPT), options=options)
+ print("chameleon: %7.2f" % t_chameleon)
+
+ t_chameleon_utf8 = timing(
+ self._chameleon(BIGTABLE_ZPT, encoding='utf-8'), options=options)
+ print("chameleon (utf-8): %7.2f" % t_chameleon_utf8)
+
+ t_tokens = timing(
+ bigtable_python_tokens, table=self.table, renderer=yield_tokens)
+ print("token: %7.2f" % t_tokens)
+
+ t_tokens_dict_version = timing(
+ bigtable_python_tokens, table=self.table,
+ renderer=yield_tokens_dict_version)
+ print("token (dict): %7.2f" % t_tokens_dict_version)
+
+ t_stream = timing(
+ bigtable_python_stream, table=self.table, renderer=yield_stream)
+ print("stream: %7.2f" % t_stream)
+
+ t_zope = timing(self._zope(BIGTABLE_ZPT), table=self.table)
+ print("zope.pagetemplate: %7.2f" % t_zope)
+ print(" %7.1fX" % (t_zope / t_chameleon))
+
+ print("--------------------------")
+ print("check: %d vs %d" % (
+ len(self._chameleon(BIGTABLE_ZPT)(options=options)),
+ len(self._zope(BIGTABLE_ZPT)(table=self.table))))
+ print("--------------------------")
+
+ @benchmark(text_("MANY STRINGS [python]"))
+ def test_many_strings(self):
+ t_chameleon = timing(self._chameleon(MANY_STRINGS_ZPT))
+ print("chameleon: %7.2f" % t_chameleon)
+ t_zope = timing(self._zope(MANY_STRINGS_ZPT))
+ print("zope.pagetemplate: %7.2f" % t_zope)
+ print(" %7.1fX" % (t_zope / t_chameleon))
+
+ print("--------------------------")
+ print("check: %d vs %d" % (
+ len(self._chameleon(MANY_STRINGS_ZPT)()),
+ len(self._zope(MANY_STRINGS_ZPT)())))
+ print("--------------------------")
+
+ @benchmark(text_("HELLO WORLD"))
+ def test_hello_world(self):
+ t_chameleon = timing(self._chameleon(HELLO_WORLD_ZPT)) * 1000
+ print("chameleon: %7.2f" % t_chameleon)
+ t_zope = timing(self._zope(HELLO_WORLD_ZPT)) * 1000
+ print("zope.pagetemplate: %7.2f" % t_zope)
+ print(" %7.1fX" % (t_zope / t_chameleon))
+
+ print("--------------------------")
+ print("check: %d vs %d" % (
+ len(self._chameleon(HELLO_WORLD_ZPT)()),
+ len(self._zope(HELLO_WORLD_ZPT)())))
+ print("--------------------------")
+
+ @benchmark(text_("I18N"))
+ def test_i18n(self):
+ from zope.i18n import translate
+ t_chameleon = timing(
+ self._chameleon(I18N_ZPT),
+ translate=translate,
+ language="klingon") * 1000
+ print("chameleon: %7.2f" % t_chameleon)
+ t_zope = timing(self._zope(I18N_ZPT), env=self.env) * 1000
+ print("zope.pagetemplate: %7.2f" % t_zope)
+ print(" %7.1fX" % (t_zope / t_chameleon))
+
+ @benchmark(text_("COMPILATION"))
+ def test_compilation(self):
+ template = self._chameleon(HELLO_WORLD_ZPT)
+
+ def chameleon_cook_and_render(template=template):
+ template.cook(HELLO_WORLD_ZPT)
+ template()
+
+ t_chameleon = timing(chameleon_cook_and_render) * 1000
+ print("chameleon: %7.2f" % t_chameleon)
+
+ template = self._zope(HELLO_WORLD_ZPT)
+
+ def zope_cook_and_render(templte=template):
+ template._cook()
+ template()
+
+ t_zope = timing(zope_cook_and_render) * 1000
+ print("zope.pagetemplate: %7.2f" % t_zope)
+ print(" %0.3fX" % (t_zope / t_chameleon))
+
+
+def start():
+ result = unittest.TestResult()
+ test = unittest.makeSuite(Benchmarks)
+ test.run(result)
+
+ for error in result.errors:
+ print("Error in %s...\n" % error[0])
+ print(error[1])
+
+ for failure in result.failures:
+ print("Failure in %s...\n" % failure[0])
+ print(failure[1])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/codegen.py b/lib/Chameleon-2.9.2/src/chameleon/codegen.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/codegen.py
@@ -0,0 +1,221 @@
+try:
+ import ast
+except ImportError:
+ from chameleon import ast24 as ast
+
+import inspect
+import textwrap
+import types
+import copy
+
+try:
+ import __builtin__ as builtins
+except ImportError:
+ import builtins
+
+reverse_builtin_map = {}
+for name, value in builtins.__dict__.items():
+ try:
+ hash(value)
+ except TypeError:
+ continue
+
+ reverse_builtin_map[value] = name
+
+try:
+ basestring
+except NameError:
+ basestring = str
+
+from .astutil import ASTCodeGenerator
+from .astutil import load
+from .astutil import store
+from .astutil import parse
+from .astutil import Builtin
+from .astutil import Symbol
+from .astutil import node_annotations
+
+from .exc import CompilationError
+
+
+try:
+ NATIVE_NUMBERS = int, float, long, bool
+except NameError:
+ NATIVE_NUMBERS = int, float, bool
+
+
+def template(function, mode='exec', **kw):
+ def wrapper(*vargs, **kwargs):
+ symbols = dict(zip(args, vargs + defaults))
+ symbols.update(kwargs)
+
+ class Visitor(ast.NodeVisitor):
+ def visit_Name(self, node):
+ value = symbols.get(node.id, self)
+ if value is not self:
+ if isinstance(value, basestring):
+ value = load(value)
+ if isinstance(value, type) or value in reverse_builtin_map:
+ name = reverse_builtin_map.get(value)
+ if name is not None:
+ value = Builtin(name)
+ else:
+ value = Symbol(value)
+
+ assert node not in node_annotations
+ assert hasattr(value, '_fields')
+ node_annotations[node] = value
+
+ expr = parse(source, mode=mode)
+ if not isinstance(function, basestring):
+ expr = expr.body[0]
+
+ Visitor().visit(expr)
+ return expr.body
+
+ if isinstance(function, basestring):
+ source = function
+ defaults = args = ()
+ return wrapper(**kw)
+
+ source = textwrap.dedent(inspect.getsource(function))
+ argspec = inspect.getargspec(function)
+ args = argspec[0]
+ defaults = argspec[3] or ()
+ return wrapper
+
+
+class TemplateCodeGenerator(ASTCodeGenerator):
+ """Extends the standard Python code generator class with handlers
+ for the helper node classes:
+
+ - Symbol (an importable value)
+ - Static (value that can be made global)
+ - Builtin (from the builtins module)
+ - Marker (short-hand for a unique static object)
+
+ """
+
+ names = ()
+
+ def __init__(self, tree):
+ self.imports = {}
+ self.defines = {}
+ self.markers = {}
+
+ # Generate code
+ super(TemplateCodeGenerator, self).__init__(tree)
+
+ def visit_Module(self, node):
+ super(TemplateCodeGenerator, self).visit_Module(node)
+
+ # Make sure we terminate the line printer
+ self.flush()
+
+ # Clear lines array for import visits
+ body = self.lines
+ self.lines = []
+
+ while self.defines:
+ name, node = self.defines.popitem()
+ assignment = ast.Assign(targets=[store(name)], value=node)
+ self.visit(assignment)
+
+ # Make sure we terminate the line printer
+ self.flush()
+
+ # Clear lines array for import visits
+ defines = self.lines
+ self.lines = []
+
+ while self.imports:
+ value, node = self.imports.popitem()
+
+ if isinstance(value, types.ModuleType):
+ stmt = ast.Import(
+ names=[ast.alias(name=value.__name__, asname=node.id)])
+ elif hasattr(value, '__name__'):
+ path = reverse_builtin_map.get(value)
+ if path is None:
+ path = value.__module__
+ name = value.__name__
+ stmt = ast.ImportFrom(
+ module=path,
+ names=[ast.alias(name=name, asname=node.id)],
+ level=0,
+ )
+ else:
+ raise TypeError(value)
+
+ self.visit(stmt)
+
+ # Clear last import
+ self.flush()
+
+ # Stich together lines
+ self.lines += defines + body
+
+ def define(self, name, node):
+ assert node is not None
+ value = self.defines.get(name)
+
+ if value is node:
+ pass
+ elif value is None:
+ self.defines[name] = node
+ else:
+ raise CompilationError(
+ "Duplicate symbol name for define.", name)
+
+ return load(name)
+
+ def require(self, value):
+ if value is None:
+ return load("None")
+
+ if isinstance(value, NATIVE_NUMBERS):
+ return ast.Num(value)
+
+ node = self.imports.get(value)
+ if node is None:
+ # we come up with a unique symbol based on the class name
+ name = "_%s" % getattr(value, '__name__', str(value)).\
+ rsplit('.', 1)[-1]
+ node = load(name)
+ self.imports[value] = store(node.id)
+
+ return node
+
+ def visit(self, node):
+ annotation = node_annotations.get(node)
+ if annotation is None:
+ super(TemplateCodeGenerator, self).visit(node)
+ else:
+ self.visit(annotation)
+
+ def visit_Comment(self, node):
+ if node.stmt is None:
+ self._new_line()
+ else:
+ self.visit(node.stmt)
+
+ for line in node.text.replace('\r', '\n').split('\n'):
+ self._new_line()
+ self._write("%s#%s" % (node.space, line))
+
+ def visit_Builtin(self, node):
+ name = load(node.id)
+ self.visit(name)
+
+ def visit_Symbol(self, node):
+ node = self.require(node.value)
+ self.visit(node)
+
+ def visit_Static(self, node):
+ if node.name is None:
+ name = "_static_%d" % id(node.value)
+ else:
+ name = node.name
+
+ node = self.define(name, node.value)
+ self.visit(node)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/compiler.py b/lib/Chameleon-2.9.2/src/chameleon/compiler.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/compiler.py
@@ -0,0 +1,1553 @@
+import re
+import sys
+import itertools
+import logging
+import threading
+import functools
+import collections
+import pickle
+import textwrap
+
+from .astutil import load
+from .astutil import store
+from .astutil import param
+from .astutil import swap
+from .astutil import subscript
+from .astutil import node_annotations
+from .astutil import annotated
+from .astutil import NameLookupRewriteVisitor
+from .astutil import Comment
+from .astutil import Symbol
+from .astutil import Builtin
+
+from .codegen import TemplateCodeGenerator
+from .codegen import template
+
+from .tal import ErrorInfo
+from .tal import NAME
+from .i18n import fast_translate
+
+from .nodes import Text
+from .nodes import Value
+from .nodes import Substitution
+from .nodes import Assignment
+from .nodes import Module
+from .nodes import Context
+
+from .tokenize import Token
+from .config import DEBUG_MODE
+from .exc import TranslationError
+from .exc import ExpressionError
+from .parser import groupdict
+
+from .utils import DebuggingOutputStream
+from .utils import char2entity
+from .utils import ListDictProxy
+from .utils import native_string
+from .utils import byte_string
+from .utils import string_type
+from .utils import unicode_string
+from .utils import version
+from .utils import ast
+from .utils import safe_native
+from .utils import builtins
+from .utils import decode_htmlentities
+
+
+if version >= (3, 0, 0):
+ long = int
+
+log = logging.getLogger('chameleon.compiler')
+
+COMPILER_INTERNALS_OR_DISALLOWED = set([
+ "econtext",
+ "rcontext",
+ "str",
+ "int",
+ "float",
+ "long",
+ "len",
+ "None",
+ "True",
+ "False",
+ "RuntimeError",
+ ])
+
+
+RE_MANGLE = re.compile('[^\w_]')
+RE_NAME = re.compile('^%s$' % NAME)
+
+if DEBUG_MODE:
+ LIST = template("cls()", cls=DebuggingOutputStream, mode="eval")
+else:
+ LIST = template("[]", mode="eval")
+
+
+def identifier(prefix, suffix=None):
+ return "__%s_%s" % (prefix, mangle(suffix or id(prefix)))
+
+
+def mangle(string):
+ return RE_MANGLE.sub('_', str(string)).replace('\n', '')
+
+
+def load_econtext(name):
+ return template("getitem(KEY)", KEY=ast.Str(s=name), mode="eval")
+
+
+def store_econtext(name):
+ name = native_string(name)
+ return subscript(name, load("econtext"), ast.Store())
+
+
+def store_rcontext(name):
+ name = native_string(name)
+ return subscript(name, load("rcontext"), ast.Store())
+
+
+def set_error(token, exception):
+ try:
+ line, column = token.location
+ filename = token.filename
+ except AttributeError:
+ line, column = 0, 0
+ filename = "<string>"
+
+ string = safe_native(token)
+
+ return template(
+ "rcontext.setdefault('__error__', [])."
+ "append((string, line, col, src, exc))",
+ string=ast.Str(s=string),
+ line=ast.Num(n=line),
+ col=ast.Num(n=column),
+ src=ast.Str(s=filename),
+ sys=Symbol(sys),
+ exc=exception,
+ )
+
+
+def try_except_wrap(stmts, token):
+ exception = template(
+ "exc_info()[1]", exc_info=Symbol(sys.exc_info), mode="eval"
+ )
+
+ body = set_error(token, exception) + template("raise")
+
+ return ast.TryExcept(
+ body=stmts,
+ handlers=[ast.ExceptHandler(body=body)],
+ )
+
+
+ at template
+def emit_node(node): # pragma: no cover
+ __append(node)
+
+
+ at template
+def emit_node_if_non_trivial(node): # pragma: no cover
+ if node is not None:
+ __append(node)
+
+
+ at template
+def emit_bool(target, s, default_marker=None,
+ default=None): # pragma: no cover
+ if target is default_marker:
+ target = default
+ elif target:
+ target = s
+ else:
+ target = None
+
+
+ at template
+def emit_convert(
+ target, encoded=byte_string, str=unicode_string,
+ long=long, type=type,
+ default_marker=None, default=None): # pragma: no cover
+ if target is None:
+ pass
+ elif target is default_marker:
+ target = default
+ else:
+ __tt = type(target)
+
+ if __tt is int or __tt is float or __tt is long:
+ target = str(target)
+ elif __tt is encoded:
+ target = decode(target)
+ elif __tt is not str:
+ try:
+ target = target.__html__
+ except AttributeError:
+ __converted = convert(target)
+ target = str(target) if target is __converted else __converted
+ else:
+ target = target()
+
+
+ at template
+def emit_translate(target, msgid, default=None): # pragma: no cover
+ target = translate(msgid, default=default, domain=__i18n_domain)
+
+
+ at template
+def emit_convert_and_escape(
+ target, quote=None, quote_entity=None, str=unicode_string, long=long,
+ type=type, encoded=byte_string,
+ default_marker=None, default=None): # pragma: no cover
+ if target is None:
+ pass
+ elif target is default_marker:
+ target = default
+ else:
+ __tt = type(target)
+
+ if __tt is int or __tt is float or __tt is long:
+ target = str(target)
+ else:
+ try:
+ if __tt is encoded:
+ target = decode(target)
+ elif __tt is not str:
+ try:
+ target = target.__html__
+ except:
+ __converted = convert(target)
+ target = str(target) if target is __converted \
+ else __converted
+ else:
+ raise RuntimeError
+ except RuntimeError:
+ target = target()
+ else:
+ if target is not None:
+ try:
+ escape = __re_needs_escape(target) is not None
+ except TypeError:
+ pass
+ else:
+ if escape:
+ # Character escape
+ if '&' in target:
+ target = target.replace('&', '&')
+ if '<' in target:
+ target = target.replace('<', '<')
+ if '>' in target:
+ target = target.replace('>', '>')
+ if quote is not None and quote in target:
+ target = target.replace(quote, quote_entity)
+
+
+class Interpolator(object):
+ braces_required_regex = re.compile(
+ r'(?<!\\)\$({(?P<expression>.*)})',
+ re.DOTALL)
+
+ braces_optional_regex = re.compile(
+ r'(?<!\\)\$({(?P<expression>.*)}|(?P<variable>[A-Za-z][A-Za-z0-9_]*))',
+ re.DOTALL)
+
+ def __init__(self, expression, braces_required, translate=False):
+ self.expression = expression
+ self.regex = self.braces_required_regex if braces_required else \
+ self.braces_optional_regex
+ self.translate = translate
+
+ def __call__(self, name, engine):
+ """The strategy is to find possible expression strings and
+ call the ``validate`` function of the parser to validate.
+
+ For every possible starting point, the longest possible
+ expression is tried first, then the second longest and so
+ forth.
+
+ Example 1:
+
+ ${'expressions use the ${<expression>} format'}
+
+ The entire expression is attempted first and it is also the
+ only one that validates.
+
+ Example 2:
+
+ ${'Hello'} ${'world!'}
+
+ Validation of the longest possible expression (the entire
+ string) will fail, while the second round of attempts,
+ ``${'Hello'}`` and ``${'world!'}`` respectively, validate.
+
+ """
+
+ body = []
+ nodes = []
+ text = self.expression
+
+ expr_map = {}
+ translate = self.translate
+
+ while text:
+ matched = text
+ m = self.regex.search(matched)
+ if m is None:
+ nodes.append(ast.Str(s=text))
+ break
+
+ part = text[:m.start()]
+ text = text[m.start():]
+
+ if part:
+ node = ast.Str(s=part)
+ nodes.append(node)
+
+ if not body:
+ target = name
+ else:
+ target = store("%s_%d" % (name.id, text.pos))
+
+ while True:
+ d = groupdict(m, matched)
+ string = d["expression"] or d["variable"] or ""
+
+ string = decode_htmlentities(string)
+
+ try:
+ compiler = engine.parse(string)
+ body += compiler.assign_text(target)
+ except ExpressionError:
+ matched = matched[m.start():m.end() - 1]
+ m = self.regex.search(matched)
+ if m is None:
+ raise
+ else:
+ break
+
+ # If one or more expressions are not simple names, we
+ # disable translation.
+ if RE_NAME.match(string) is None:
+ translate = False
+
+ # if this is the first expression, use the provided
+ # assignment name; otherwise, generate one (here based
+ # on the string position)
+ node = load(target.id)
+ nodes.append(node)
+
+ expr_map[node] = safe_native(string)
+
+ text = text[len(m.group()):]
+
+ if len(nodes) == 1:
+ target = nodes[0]
+
+ if translate and isinstance(target, ast.Str):
+ target = template(
+ "translate(msgid, domain=__i18n_domain, context=econtext)",
+ msgid=target, mode="eval",
+ )
+ else:
+ if translate:
+ formatting_string = ""
+ keys = []
+ values = []
+
+ for node in nodes:
+ if isinstance(node, ast.Str):
+ formatting_string += node.s
+ else:
+ string = expr_map[node]
+ formatting_string += "${%s}" % string
+ keys.append(ast.Str(s=string))
+ values.append(node)
+
+ target = template(
+ "translate(msgid, mapping=mapping, domain=__i18n_domain, context=econtext)",
+ msgid=ast.Str(s=formatting_string),
+ mapping=ast.Dict(keys=keys, values=values),
+ mode="eval"
+ )
+ else:
+ nodes = [
+ template(
+ "NODE if NODE is not None else ''",
+ NODE=node, mode="eval"
+ )
+ for node in nodes
+ ]
+
+ target = ast.BinOp(
+ left=ast.Str(s="%s" * len(nodes)),
+ op=ast.Mod(),
+ right=ast.Tuple(elts=nodes, ctx=ast.Load()))
+
+ body += [ast.Assign(targets=[name], value=target)]
+ return body
+
+
+class ExpressionEngine(object):
+ """Expression engine.
+
+ This test demonstrates how to configure and invoke the engine.
+
+ >>> from chameleon import tales
+ >>> parser = tales.ExpressionParser({
+ ... 'python': tales.PythonExpr,
+ ... 'not': tales.NotExpr,
+ ... 'exists': tales.ExistsExpr,
+ ... 'string': tales.StringExpr,
+ ... }, 'python')
+
+ >>> engine = ExpressionEngine(parser)
+
+ An expression evaluation function:
+
+ >>> eval = lambda expression: tales.test(
+ ... tales.IdentityExpr(expression), engine)
+
+ We have provided 'python' as the default expression type. This
+ means that when no prefix is given, the expression is evaluated as
+ a Python expression:
+
+ >>> eval('not False')
+ True
+
+ Note that the ``type`` prefixes bind left. If ``not`` and
+ ``exits`` are two expression type prefixes, consider the
+ following::
+
+ >>> eval('not: exists: int(None)')
+ True
+
+ The pipe operator binds right. In the following example, but
+ arguments are evaluated against ``not: exists: ``.
+
+ >>> eval('not: exists: help')
+ False
+
+ >>> eval('string:test ${1}${2}')
+ 'test 12'
+
+ """
+
+ supported_char_escape_set = set(('&', '<', '>'))
+
+ def __init__(self, parser, char_escape=(),
+ default=None, default_marker=None):
+ self._parser = parser
+ self._char_escape = char_escape
+ self._default = default
+ self._default_marker = default_marker
+
+ def __call__(self, string, target):
+ # BBB: This method is deprecated. Instead, a call should first
+ # be made to ``parse`` and then one of the assignment methods
+ # ("value" or "text").
+
+ compiler = self.parse(string)
+ return compiler(string, target)
+
+ def parse(self, string):
+ expression = self._parser(string)
+ compiler = self.get_compiler(expression, string)
+ return ExpressionCompiler(compiler, self)
+
+ def get_compiler(self, expression, string):
+ def compiler(target, engine, result_type=None, *args):
+ stmts = expression(target, engine)
+
+ if result_type is not None:
+ method = getattr(self, '_convert_%s' % result_type)
+ steps = method(target, *args)
+ stmts.extend(steps)
+
+ return [try_except_wrap(stmts, string)]
+
+ return compiler
+
+ def _convert_bool(self, target, s):
+ """Converts value given by ``target`` to a string ``s`` if the
+ target is a true value, otherwise ``None``.
+ """
+
+ return emit_bool(
+ target, ast.Str(s=s),
+ default=self._default,
+ default_marker=self._default_marker
+ )
+
+ def _convert_text(self, target):
+ """Converts value given by ``target`` to text."""
+
+ if self._char_escape:
+ # This is a cop-out - we really only support a very select
+ # set of escape characters
+ other = set(self._char_escape) - self.supported_char_escape_set
+
+ if other:
+ for supported in '"', '\'', '':
+ if supported in self._char_escape:
+ quote = supported
+ break
+ else:
+ raise RuntimeError(
+ "Unsupported escape set: %s." % repr(self._char_escape)
+ )
+ else:
+ quote = '\0'
+
+ entity = char2entity(quote or '\0')
+
+ return emit_convert_and_escape(
+ target,
+ quote=ast.Str(s=quote),
+ quote_entity=ast.Str(s=entity),
+ default=self._default,
+ default_marker=self._default_marker,
+ )
+
+ return emit_convert(
+ target,
+ default=self._default,
+ default_marker=self._default_marker,
+ )
+
+
+class ExpressionCompiler(object):
+ def __init__(self, compiler, engine):
+ self.compiler = compiler
+ self.engine = engine
+
+ def assign_bool(self, target, s):
+ return self.compiler(target, self.engine, "bool", s)
+
+ def assign_text(self, target):
+ return self.compiler(target, self.engine, "text")
+
+ def assign_value(self, target):
+ return self.compiler(target, self.engine)
+
+
+class ExpressionEvaluator(object):
+ """Evaluates dynamic expression.
+
+ This is not particularly efficient, but supported for legacy
+ applications.
+
+ >>> from chameleon import tales
+ >>> parser = tales.ExpressionParser({'python': tales.PythonExpr}, 'python')
+ >>> engine = functools.partial(ExpressionEngine, parser)
+
+ >>> evaluate = ExpressionEvaluator(engine, {
+ ... 'foo': 'bar',
+ ... })
+
+ The evaluation function is passed the local and remote context,
+ the expression type and finally the expression.
+
+ >>> evaluate({'boo': 'baz'}, {}, 'python', 'foo + boo')
+ 'barbaz'
+
+ The cache is now primed:
+
+ >>> evaluate({'boo': 'baz'}, {}, 'python', 'foo + boo')
+ 'barbaz'
+
+ Note that the call method supports currying of the expression
+ argument:
+
+ >>> python = evaluate({'boo': 'baz'}, {}, 'python')
+ >>> python('foo + boo')
+ 'barbaz'
+
+ """
+
+ __slots__ = "_engine", "_cache", "_names", "_builtins"
+
+ def __init__(self, engine, builtins):
+ self._engine = engine
+ self._names, self._builtins = zip(*builtins.items())
+ self._cache = {}
+
+ def __call__(self, econtext, rcontext, expression_type, string=None):
+ if string is None:
+ return functools.partial(
+ self.__call__, econtext, rcontext, expression_type
+ )
+
+ expression = "%s:%s" % (expression_type, string)
+
+ try:
+ evaluate = self._cache[expression]
+ except KeyError:
+ assignment = Assignment(["_result"], expression, True)
+ module = Module("evaluate", Context(assignment))
+
+ compiler = Compiler(
+ self._engine, module, ('econtext', 'rcontext') + self._names
+ )
+
+ env = {}
+ exec(compiler.code, env)
+ evaluate = self._cache[expression] = env["evaluate"]
+
+ evaluate(econtext, rcontext, *self._builtins)
+ return econtext['_result']
+
+
+class NameTransform(object):
+ """
+ >>> nt = NameTransform(
+ ... set(('foo', 'bar', )), {'boo': 'boz'},
+ ... ('econtext', ),
+ ... )
+
+ >>> def test(node):
+ ... rewritten = nt(node)
+ ... module = ast.Module([ast.fix_missing_locations(rewritten)])
+ ... codegen = TemplateCodeGenerator(module)
+ ... return codegen.code
+
+ Any odd name:
+
+ >>> test(load('frobnitz'))
+ "getitem('frobnitz')"
+
+ A 'builtin' name will first be looked up via ``get`` allowing fall
+ back to the global builtin value:
+
+ >>> test(load('foo'))
+ "get('foo', foo)"
+
+ Internal names (with two leading underscores) are left alone:
+
+ >>> test(load('__internal'))
+ '__internal'
+
+ Compiler internals or disallowed names:
+
+ >>> test(load('econtext'))
+ 'econtext'
+
+ Aliased names:
+
+ >>> test(load('boo'))
+ 'boz'
+
+ """
+
+ def __init__(self, builtins, aliases, internals):
+ self.builtins = builtins
+ self.aliases = aliases
+ self.internals = internals
+
+ def __call__(self, node):
+ name = node.id
+
+ # Don't rewrite names that begin with an underscore; they are
+ # internal and can be assumed to be locally defined. This
+ # policy really should be part of the template program, not
+ # defined here in the compiler.
+ if name.startswith('__') or name in self.internals:
+ return node
+
+ if isinstance(node.ctx, ast.Store):
+ return store_econtext(name)
+
+ aliased = self.aliases.get(name)
+ if aliased is not None:
+ return load(aliased)
+
+ # If the name is a Python global, first try acquiring it from
+ # the dynamic context, then fall back to the global.
+ if name in self.builtins:
+ return template(
+ "get(key, name)",
+ mode="eval",
+ key=ast.Str(s=name),
+ name=load(name),
+ )
+
+ # Otherwise, simply acquire it from the dynamic context.
+ return load_econtext(name)
+
+
+class ExpressionTransform(object):
+ """Internal wrapper to transform expression nodes into assignment
+ statements.
+
+ The node input may use the provided expression engine, but other
+ expression node types are supported such as ``Builtin`` which
+ simply resolves a built-in name.
+
+ Used internally be the compiler.
+ """
+
+ loads_symbol = Symbol(pickle.loads)
+
+ def __init__(self, engine_factory, cache, visitor, strict=True):
+ self.engine_factory = engine_factory
+ self.cache = cache
+ self.strict = strict
+ self.visitor = visitor
+
+ def __call__(self, expression, target):
+ if isinstance(target, string_type):
+ target = store(target)
+
+ try:
+ stmts = self.translate(expression, target)
+ except ExpressionError:
+ if self.strict:
+ raise
+
+ exc = sys.exc_info()[1]
+ p = pickle.dumps(exc)
+
+ stmts = template(
+ "__exc = loads(p)", loads=self.loads_symbol, p=ast.Str(s=p)
+ )
+
+ token = Token(exc.token, exc.offset, filename=exc.filename)
+
+ stmts += set_error(token, load("__exc"))
+ stmts += [ast.Raise(exc=load("__exc"))]
+
+ # Apply visitor to each statement
+ for stmt in stmts:
+ self.visitor(stmt)
+
+ return stmts
+
+ def translate(self, expression, target):
+ if isinstance(target, string_type):
+ target = store(target)
+
+ cached = self.cache.get(expression)
+
+ if cached is not None:
+ stmts = [ast.Assign(targets=[target], value=cached)]
+ elif isinstance(expression, ast.expr):
+ stmts = [ast.Assign(targets=[target], value=expression)]
+ else:
+ # The engine interface supports simple strings, which
+ # default to expression nodes
+ if isinstance(expression, string_type):
+ expression = Value(expression, True)
+
+ kind = type(expression).__name__
+ visitor = getattr(self, "visit_%s" % kind)
+ stmts = visitor(expression, target)
+
+ # Add comment
+ target_id = getattr(target, "id", target)
+ comment = Comment(" %r -> %s" % (expression, target_id))
+ stmts.insert(0, comment)
+
+ return stmts
+
+ def visit_Value(self, node, target):
+ engine = self.engine_factory()
+ compiler = engine.parse(node.value)
+ return compiler.assign_value(target)
+
+ def visit_Default(self, node, target):
+ value = annotated(node.marker)
+ return [ast.Assign(targets=[target], value=value)]
+
+ def visit_Substitution(self, node, target):
+ engine = self.engine_factory(
+ char_escape=node.char_escape,
+ default=node.default,
+ )
+ compiler = engine.parse(node.value)
+ return compiler.assign_text(target)
+
+ def visit_Negate(self, node, target):
+ return self.translate(node.value, target) + \
+ template("TARGET = not TARGET", TARGET=target)
+
+ def visit_Identity(self, node, target):
+ expression = self.translate(node.expression, "__expression")
+ value = self.translate(node.value, "__value")
+
+ return expression + value + \
+ template("TARGET = __expression is __value", TARGET=target)
+
+ def visit_Equality(self, node, target):
+ expression = self.translate(node.expression, "__expression")
+ value = self.translate(node.value, "__value")
+
+ return expression + value + \
+ template("TARGET = __expression == __value", TARGET=target)
+
+ def visit_Boolean(self, node, target):
+ engine = self.engine_factory()
+ compiler = engine.parse(node.value)
+ return compiler.assign_bool(target, node.s)
+
+ def visit_Interpolation(self, node, target):
+ expr = node.value
+ if isinstance(expr, Substitution):
+ engine = self.engine_factory(
+ char_escape=expr.char_escape,
+ default=expr.default,
+ )
+ elif isinstance(expr, Value):
+ engine = self.engine_factory()
+ else:
+ raise RuntimeError("Bad value: %r." % node.value)
+
+ interpolator = Interpolator(
+ expr.value, node.braces_required, node.translation
+ )
+
+ compiler = engine.get_compiler(interpolator, expr.value)
+ return compiler(target, engine)
+
+ def visit_Translate(self, node, target):
+ if node.msgid is not None:
+ msgid = ast.Str(s=node.msgid)
+ else:
+ msgid = target
+ return self.translate(node.node, target) + \
+ emit_translate(target, msgid, default=target)
+
+ def visit_Static(self, node, target):
+ value = annotated(node)
+ return [ast.Assign(targets=[target], value=value)]
+
+ def visit_Builtin(self, node, target):
+ value = annotated(node)
+ return [ast.Assign(targets=[target], value=value)]
+
+
+class Compiler(object):
+ """Generic compiler class.
+
+ Iterates through nodes and yields Python statements which form a
+ template program.
+ """
+
+ exceptions = NameError, \
+ ValueError, \
+ AttributeError, \
+ LookupError, \
+ TypeError
+
+ defaults = {
+ 'translate': Symbol(fast_translate),
+ 'decode': Builtin("str"),
+ 'convert': Builtin("str"),
+ }
+
+ lock = threading.Lock()
+
+ global_builtins = set(builtins.__dict__)
+
+ def __init__(self, engine_factory, node, builtins={}, strict=True):
+ self._scopes = [set()]
+ self._expression_cache = {}
+ self._translations = []
+ self._builtins = builtins
+ self._aliases = [{}]
+ self._macros = []
+ self._current_slot = []
+
+ internals = COMPILER_INTERNALS_OR_DISALLOWED | \
+ set(self.defaults)
+
+ transform = NameTransform(
+ self.global_builtins | set(builtins),
+ ListDictProxy(self._aliases),
+ internals,
+ )
+
+ self._visitor = visitor = NameLookupRewriteVisitor(transform)
+
+ self._engine = ExpressionTransform(
+ engine_factory,
+ self._expression_cache,
+ visitor,
+ strict=strict,
+ )
+
+ if isinstance(node_annotations, dict):
+ self.lock.acquire()
+ backup = node_annotations.copy()
+ else:
+ backup = None
+
+ try:
+ module = ast.Module([])
+ module.body += self.visit(node)
+ ast.fix_missing_locations(module)
+ generator = TemplateCodeGenerator(module)
+ finally:
+ if backup is not None:
+ node_annotations.clear()
+ node_annotations.update(backup)
+ self.lock.release()
+
+ self.code = generator.code
+
+ def visit(self, node):
+ if node is None:
+ return ()
+ kind = type(node).__name__
+ visitor = getattr(self, "visit_%s" % kind)
+ iterator = visitor(node)
+ return list(iterator)
+
+ def visit_Sequence(self, node):
+ for item in node.items:
+ for stmt in self.visit(item):
+ yield stmt
+
+ def visit_Element(self, node):
+ self._aliases.append(self._aliases[-1].copy())
+
+ for stmt in self.visit(node.start):
+ yield stmt
+
+ for stmt in self.visit(node.content):
+ yield stmt
+
+ if node.end is not None:
+ for stmt in self.visit(node.end):
+ yield stmt
+
+ self._aliases.pop()
+
+ def visit_Module(self, node):
+ body = []
+
+ body += template("import re")
+ body += template("import functools")
+ body += template("__marker = object()")
+ body += template(
+ r"g_re_amp = re.compile(r'&(?!([A-Za-z]+|#[0-9]+);)')"
+ )
+ body += template(
+ r"g_re_needs_escape = re.compile(r'[&<>\"\']').search")
+
+ body += template(
+ r"__re_whitespace = "
+ r"functools.partial(re.compile('\s+').sub, ' ')",
+ )
+
+ # Visit module content
+ program = self.visit(node.program)
+
+ body += [ast.FunctionDef(
+ name=node.name, args=ast.arguments(
+ args=[param(b) for b in self._builtins],
+ defaults=(),
+ ),
+ body=program
+ )]
+
+ return body
+
+ def visit_MacroProgram(self, node):
+ functions = []
+
+ # Visit defined macros
+ macros = getattr(node, "macros", ())
+ names = []
+ for macro in macros:
+ stmts = self.visit(macro)
+ function = stmts[-1]
+ names.append(function.name)
+ functions += stmts
+
+ # Return function dictionary
+ functions += [ast.Return(value=ast.Dict(
+ keys=[ast.Str(s=name) for name in names],
+ values=[load(name) for name in names],
+ ))]
+
+ return functions
+
+ def visit_Context(self, node):
+ return template("getitem = econtext.__getitem__") + \
+ template("get = econtext.get") + \
+ self.visit(node.node)
+
+ def visit_Macro(self, node):
+ body = []
+
+ # Initialization
+ body += template("__append = __stream.append")
+ body += template("__re_amp = g_re_amp")
+ body += template("__re_needs_escape = g_re_needs_escape")
+
+ # Resolve defaults
+ for name in self.defaults:
+ body += template(
+ "NAME = econtext[KEY]",
+ NAME=name, KEY=ast.Str(s="__" + name)
+ )
+
+ # Internal set of defined slots
+ self._slots = set()
+
+ # Visit macro body
+ nodes = itertools.chain(*tuple(map(self.visit, node.body)))
+
+ # Slot resolution
+ for name in self._slots:
+ body += template(
+ "try: NAME = econtext[KEY].pop()\n"
+ "except: NAME = None",
+ KEY=ast.Str(s=name), NAME=store(name))
+
+ # Append visited nodes
+ body += nodes
+
+ function_name = "render" if node.name is None else \
+ "render_%s" % mangle(node.name)
+
+ function = ast.FunctionDef(
+ name=function_name, args=ast.arguments(
+ args=[
+ param("__stream"),
+ param("econtext"),
+ param("rcontext"),
+ param("__i18n_domain"),
+ ],
+ defaults=[load("None")],
+ ),
+ body=body
+ )
+
+ yield function
+
+ def visit_Text(self, node):
+ return emit_node(ast.Str(s=node.value))
+
+ def visit_Domain(self, node):
+ backup = "__previous_i18n_domain_%d" % id(node)
+ return template("BACKUP = __i18n_domain", BACKUP=backup) + \
+ template("__i18n_domain = NAME", NAME=ast.Str(s=node.name)) + \
+ self.visit(node.node) + \
+ template("__i18n_domain = BACKUP", BACKUP=backup)
+
+ def visit_OnError(self, node):
+ body = []
+
+ fallback = identifier("__fallback")
+ body += template("fallback = len(__stream)", fallback=fallback)
+
+ self._enter_assignment((node.name, ))
+ fallback_body = self.visit(node.fallback)
+ self._leave_assignment((node.name, ))
+
+ error_assignment = template(
+ "econtext[key] = cls(__exc, rcontext['__error__'][-1][1:3])",
+ cls=ErrorInfo,
+ key=ast.Str(s=node.name),
+ )
+
+ body += [ast.TryExcept(
+ body=self.visit(node.node),
+ handlers=[ast.ExceptHandler(
+ type=ast.Tuple(elts=[Builtin("Exception")], ctx=ast.Load()),
+ name=store("__exc"),
+ body=(error_assignment + \
+ template("del __stream[fallback:]", fallback=fallback) + \
+ fallback_body
+ ),
+ )]
+ )]
+
+ return body
+
+ def visit_Content(self, node):
+ name = "__content"
+ body = self._engine(node.expression, store(name))
+
+ if node.translate:
+ body += emit_translate(name, name)
+
+ if node.char_escape:
+ body += emit_convert_and_escape(name)
+ else:
+ body += emit_convert(name)
+
+ body += template("if NAME is not None: __append(NAME)", NAME=name)
+
+ return body
+
+ def visit_Interpolation(self, node):
+ name = identifier("content")
+ return self._engine(node, name) + \
+ emit_node_if_non_trivial(name)
+
+ def visit_Alias(self, node):
+ assert len(node.names) == 1
+ name = node.names[0]
+ target = self._aliases[-1][name] = identifier(name, id(node))
+ return self._engine(node.expression, target)
+
+ def visit_Assignment(self, node):
+ for name in node.names:
+ if name in COMPILER_INTERNALS_OR_DISALLOWED:
+ raise TranslationError(
+ "Name disallowed by compiler.", name
+ )
+
+ if name.startswith('__'):
+ raise TranslationError(
+ "Name disallowed by compiler (double underscore).",
+ name
+ )
+
+ assignment = self._engine(node.expression, store("__value"))
+
+ if len(node.names) != 1:
+ target = ast.Tuple(
+ elts=[store_econtext(name) for name in node.names],
+ ctx=ast.Store(),
+ )
+ else:
+ target = store_econtext(node.names[0])
+
+ assignment.append(ast.Assign(targets=[target], value=load("__value")))
+
+ for name in node.names:
+ if not node.local:
+ assignment += template(
+ "rcontext[KEY] = __value", KEY=ast.Str(s=native_string(name))
+ )
+
+ return assignment
+
+ def visit_Define(self, node):
+ scope = set(self._scopes[-1])
+ self._scopes.append(scope)
+
+ for assignment in node.assignments:
+ if assignment.local:
+ for stmt in self._enter_assignment(assignment.names):
+ yield stmt
+
+ for stmt in self.visit(assignment):
+ yield stmt
+
+ for stmt in self.visit(node.node):
+ yield stmt
+
+ for assignment in node.assignments:
+ if assignment.local:
+ for stmt in self._leave_assignment(assignment.names):
+ yield stmt
+
+ self._scopes.pop()
+
+ def visit_Omit(self, node):
+ return self.visit_Condition(node)
+
+ def visit_Condition(self, node):
+ target = "__condition"
+ assignment = self._engine(node.expression, target)
+
+ assert assignment
+
+ for stmt in assignment:
+ yield stmt
+
+ body = self.visit(node.node) or [ast.Pass()]
+
+ orelse = getattr(node, "orelse", None)
+ if orelse is not None:
+ orelse = self.visit(orelse)
+
+ test = load(target)
+
+ yield ast.If(test=test, body=body, orelse=orelse)
+
+ def visit_Translate(self, node):
+ """Translation.
+
+ Visit items and assign output to a default value.
+
+ Finally, compile a translation expression and use either
+ result or default.
+ """
+
+ body = []
+
+ # Track the blocks of this translation
+ self._translations.append(set())
+
+ # Prepare new stream
+ append = identifier("append", id(node))
+ stream = identifier("stream", id(node))
+ body += template("s = new_list", s=stream, new_list=LIST) + \
+ template("a = s.append", a=append, s=stream)
+
+ # Visit body to generate the message body
+ code = self.visit(node.node)
+ swap(ast.Suite(body=code), load(append), "__append")
+ body += code
+
+ # Reduce white space and assign as message id
+ msgid = identifier("msgid", id(node))
+ body += template(
+ "msgid = __re_whitespace(''.join(stream)).strip()",
+ msgid=msgid, stream=stream
+ )
+
+ default = msgid
+
+ # Compute translation block mapping if applicable
+ names = self._translations[-1]
+ if names:
+ keys = []
+ values = []
+
+ for name in names:
+ stream, append = self._get_translation_identifiers(name)
+ keys.append(ast.Str(s=name))
+ values.append(load(stream))
+
+ # Initialize value
+ body.insert(
+ 0, ast.Assign(
+ targets=[store(stream)],
+ value=ast.Str(s=native_string(""))))
+
+ mapping = ast.Dict(keys=keys, values=values)
+ else:
+ mapping = None
+
+ # if this translation node has a name, use it as the message id
+ if node.msgid:
+ msgid = ast.Str(s=node.msgid)
+
+ # emit the translation expression
+ body += template(
+ "__append(translate("
+ "msgid, mapping=mapping, default=default, domain=__i18n_domain, context=econtext))",
+ msgid=msgid, default=default, mapping=mapping
+ )
+
+ # pop away translation block reference
+ self._translations.pop()
+
+ return body
+
+ def visit_Start(self, node):
+ try:
+ line, column = node.prefix.location
+ except AttributeError:
+ line, column = 0, 0
+
+ yield Comment(
+ " %s%s ... (%d:%d)\n"
+ " --------------------------------------------------------" % (
+ node.prefix, node.name, line, column))
+
+ if node.attributes:
+ for stmt in emit_node(ast.Str(s=node.prefix + node.name)):
+ yield stmt
+
+ for attribute in node.attributes:
+ for stmt in self.visit(attribute):
+ yield stmt
+
+ for stmt in emit_node(ast.Str(s=node.suffix)):
+ yield stmt
+ else:
+ for stmt in emit_node(
+ ast.Str(s=node.prefix + node.name + node.suffix)):
+ yield stmt
+
+ def visit_End(self, node):
+ for stmt in emit_node(ast.Str(
+ s=node.prefix + node.name + node.space + node.suffix)):
+ yield stmt
+
+ def visit_Attribute(self, node):
+ f = node.space + node.name + node.eq + node.quote + "%s" + node.quote
+
+ # Static attributes are just outputted directly
+ if isinstance(node.expression, ast.Str):
+ s = f % node.expression.s
+ return template("__append(S)", S=ast.Str(s=s))
+
+ target = identifier("attr", node.name)
+ body = self._engine(node.expression, store(target))
+ return body + template(
+ "if TARGET is not None: __append(FORMAT % TARGET)",
+ FORMAT=ast.Str(s=f),
+ TARGET=target,
+ )
+
+ def visit_Cache(self, node):
+ body = []
+
+ for expression in node.expressions:
+ name = identifier("cache", id(expression))
+ target = store(name)
+
+ # Skip re-evaluation
+ if self._expression_cache.get(expression):
+ continue
+
+ body += self._engine(expression, target)
+ self._expression_cache[expression] = target
+
+ body += self.visit(node.node)
+
+ return body
+
+ def visit_UseInternalMacro(self, node):
+ if node.name is None:
+ render = "render"
+ else:
+ render = "render_%s" % mangle(node.name)
+
+ return template(
+ "f(__stream, econtext.copy(), rcontext, __i18n_domain)",
+ f=render) + \
+ template("econtext.update(rcontext)")
+
+ def visit_DefineSlot(self, node):
+ name = "__slot_%s" % mangle(node.name)
+ body = self.visit(node.node)
+
+ self._slots.add(name)
+
+ orelse = template(
+ "SLOT(__stream, econtext.copy(), rcontext)",
+ SLOT=name)
+ test = ast.Compare(
+ left=load(name),
+ ops=[ast.Is()],
+ comparators=[load("None")]
+ )
+
+ return [
+ ast.If(test=test, body=body or [ast.Pass()], orelse=orelse)
+ ]
+
+ def visit_Name(self, node):
+ """Translation name."""
+
+ if not self._translations:
+ raise TranslationError(
+ "Not allowed outside of translation.", node.name)
+
+ if node.name in self._translations[-1]:
+ raise TranslationError(
+ "Duplicate translation name: %s." % node.name)
+
+ self._translations[-1].add(node.name)
+ body = []
+
+ # prepare new stream
+ stream, append = self._get_translation_identifiers(node.name)
+ body += template("s = new_list", s=stream, new_list=LIST) + \
+ template("a = s.append", a=append, s=stream)
+
+ # generate code
+ code = self.visit(node.node)
+ swap(ast.Suite(body=code), load(append), "__append")
+ body += code
+
+ # output msgid
+ text = Text('${%s}' % node.name)
+ body += self.visit(text)
+
+ # Concatenate stream
+ body += template("stream = ''.join(stream)", stream=stream)
+
+ return body
+
+ def visit_CodeBlock(self, node):
+ stmts = template(textwrap.dedent(node.source.strip('\n')))
+
+ for stmt in stmts:
+ self._visitor(stmt)
+
+ return stmts
+
+ def visit_UseExternalMacro(self, node):
+ self._macros.append(node.extend)
+
+ callbacks = []
+ for slot in node.slots:
+ key = "__slot_%s" % mangle(slot.name)
+ fun = "__fill_%s" % mangle(slot.name)
+
+ self._current_slot.append(slot.name)
+
+ body = template("getitem = econtext.__getitem__") + \
+ template("get = econtext.get") + \
+ self.visit(slot.node)
+
+ assert self._current_slot.pop() == slot.name
+
+ callbacks.append(
+ ast.FunctionDef(
+ name=fun,
+ args=ast.arguments(
+ args=[
+ param("__stream"),
+ param("econtext"),
+ param("rcontext"),
+ param("__i18n_domain"),
+ ],
+ defaults=[load("__i18n_domain")],
+ ),
+ body=body or [ast.Pass()],
+ ))
+
+ key = ast.Str(s=key)
+
+ assignment = template(
+ "_slots = econtext[KEY] = DEQUE((NAME,))",
+ KEY=key, NAME=fun, DEQUE=Symbol(collections.deque),
+ )
+
+ if node.extend:
+ append = template("_slots.appendleft(NAME)", NAME=fun)
+
+ assignment = [ast.TryExcept(
+ body=template("_slots = getitem(KEY)", KEY=key),
+ handlers=[ast.ExceptHandler(body=assignment)],
+ orelse=append,
+ )]
+
+ callbacks.extend(assignment)
+
+ assert self._macros.pop() == node.extend
+
+ assignment = self._engine(node.expression, store("__macro"))
+
+ return (
+ callbacks + \
+ assignment + \
+ template(
+ "__macro.include(__stream, econtext.copy(), " \
+ "rcontext, __i18n_domain)") + \
+ template("econtext.update(rcontext)")
+ )
+
+ def visit_Repeat(self, node):
+ # Used for loop variable definition and restore
+ self._scopes.append(set())
+
+ # Variable assignment and repeat key for single- and
+ # multi-variable repeat clause
+ if node.local:
+ contexts = "econtext",
+ else:
+ contexts = "econtext", "rcontext"
+
+ for name in node.names:
+ if name in COMPILER_INTERNALS_OR_DISALLOWED:
+ raise TranslationError(
+ "Name disallowed by compiler.", name
+ )
+
+ if len(node.names) > 1:
+ targets = [
+ ast.Tuple(elts=[
+ subscript(native_string(name), load(context), ast.Store())
+ for name in node.names], ctx=ast.Store())
+ for context in contexts
+ ]
+
+ key = ast.Tuple(
+ elts=[ast.Str(s=name) for name in node.names],
+ ctx=ast.Load())
+ else:
+ name = node.names[0]
+ targets = [
+ subscript(native_string(name), load(context), ast.Store())
+ for context in contexts
+ ]
+
+ key = ast.Str(s=node.names[0])
+
+ index = identifier("__index", id(node))
+ assignment = [ast.Assign(targets=targets, value=load("__item"))]
+
+ # Make repeat assignment in outer loop
+ names = node.names
+ local = node.local
+
+ outer = self._engine(node.expression, store("__iterator"))
+
+ if local:
+ outer[:] = list(self._enter_assignment(names)) + outer
+
+ outer += template(
+ "__iterator, INDEX = getitem('repeat')(key, __iterator)",
+ key=key, INDEX=index
+ )
+
+ # Set a trivial default value for each name assigned to make
+ # sure we assign a value even if the iteration is empty
+ outer += [ast.Assign(
+ targets=[store_econtext(name)
+ for name in node.names],
+ value=load("None"))
+ ]
+
+ # Compute inner body
+ inner = self.visit(node.node)
+
+ # After each iteration, decrease the index
+ inner += template("index -= 1", index=index)
+
+ # For items up to N - 1, emit repeat whitespace
+ inner += template(
+ "if INDEX > 0: __append(WHITESPACE)",
+ INDEX=index, WHITESPACE=ast.Str(s=node.whitespace)
+ )
+
+ # Main repeat loop
+ outer += [ast.For(
+ target=store("__item"),
+ iter=load("__iterator"),
+ body=assignment + inner,
+ )]
+
+ # Finally, clean up assignment if it's local
+ if outer:
+ outer += self._leave_assignment(names)
+
+ self._scopes.pop()
+
+ return outer
+
+ def _get_translation_identifiers(self, name):
+ assert self._translations
+ prefix = id(self._translations[-1])
+ stream = identifier("stream_%d" % prefix, name)
+ append = identifier("append_%d" % prefix, name)
+ return stream, append
+
+ def _enter_assignment(self, names):
+ for name in names:
+ for stmt in template(
+ "BACKUP = get(KEY, __marker)",
+ BACKUP=identifier("backup_%s" % name, id(names)),
+ KEY=ast.Str(s=native_string(name)),
+ ):
+ yield stmt
+
+ def _leave_assignment(self, names):
+ for name in names:
+ for stmt in template(
+ "if BACKUP is __marker: del econtext[KEY]\n"
+ "else: econtext[KEY] = BACKUP",
+ BACKUP=identifier("backup_%s" % name, id(names)),
+ KEY=ast.Str(s=native_string(name)),
+ ):
+ yield stmt
diff --git a/lib/Chameleon-2.9.2/src/chameleon/config.py b/lib/Chameleon-2.9.2/src/chameleon/config.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/config.py
@@ -0,0 +1,47 @@
+import os
+import logging
+
+log = logging.getLogger('chameleon.config')
+
+# Define which values are read as true
+TRUE = ('y', 'yes', 't', 'true', 'on', '1')
+
+# If eager parsing is enabled, templates are parsed upon
+# instantiation, rather than when first called upon; this mode is
+# useful for verifying validity of templates across a project
+EAGER_PARSING = os.environ.pop('CHAMELEON_EAGER', 'false')
+EAGER_PARSING = EAGER_PARSING.lower() in TRUE
+
+# Debug mode is mostly useful for debugging the template engine
+# itself. When enabled, generated source code is written to disk to
+# ease step-debugging and some log levels are lowered to increase
+# output. Also, the generated source code is available in the
+# ``source`` attribute of the template instance if compilation
+# succeeded.
+DEBUG_MODE = os.environ.pop('CHAMELEON_DEBUG', 'false')
+DEBUG_MODE = DEBUG_MODE.lower() in TRUE
+
+# If a cache directory is specified, template source code will be
+# persisted on disk and reloaded between sessions
+path = os.environ.pop('CHAMELEON_CACHE', None)
+if path is not None:
+ CACHE_DIRECTORY = os.path.abspath(path)
+ if not os.path.exists(CACHE_DIRECTORY):
+ raise ValueError(
+ "Cache directory does not exist: %s." % CACHE_DIRECTORY
+ )
+ log.info("directory cache: %s." % CACHE_DIRECTORY)
+else:
+ CACHE_DIRECTORY = None
+
+# When auto-reload is enabled, templates are reloaded on file change.
+AUTO_RELOAD = os.environ.pop('CHAMELEON_RELOAD', 'false')
+AUTO_RELOAD = AUTO_RELOAD.lower() in TRUE
+
+for key in os.environ:
+ if key.lower().startswith('chameleon'):
+ log.warn("unknown environment variable set: \"%s\"." % key)
+
+# This is the slice length of the expression displayed in the
+# formatted exception string
+SOURCE_EXPRESSION_MARKER_LENGTH = 60
diff --git a/lib/Chameleon-2.9.2/src/chameleon/exc.py b/lib/Chameleon-2.9.2/src/chameleon/exc.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/exc.py
@@ -0,0 +1,289 @@
+# -*- coding: utf-8 -*-
+
+import traceback
+
+from .utils import format_kwargs
+from .utils import safe_native
+from .tokenize import Token
+from .config import SOURCE_EXPRESSION_MARKER_LENGTH as LENGTH
+
+
+def compute_source_marker(line, column, expression, size):
+ """Computes source marker location string.
+
+ >>> def test(l, c, e, s):
+ ... s, marker = compute_source_marker(l, c, e, s)
+ ... out = s + '\\n' + marker
+ ...
+ ... # Replace dot with middle-dot to work around doctest ellipsis
+ ... print(out.replace('...', '···'))
+
+ >>> test('foo bar', 4, 'bar', 7)
+ foo bar
+ ^^^
+
+ >>> test('foo ${bar}', 4, 'bar', 10)
+ foo ${bar}
+ ^^^
+
+ >>> test(' foo bar', 6, 'bar', 6)
+ ··· oo bar
+ ^^^
+
+ >>> test(' foo bar baz ', 6, 'bar', 6)
+ ··· o bar ···
+ ^^^
+
+ The entire expression is always shown, even if ``size`` does not
+ accomodate for it.
+
+ >>> test(' foo bar baz ', 6, 'bar baz', 10)
+ ··· oo bar baz
+ ^^^^^^^
+
+ >>> test(' foo bar', 10, 'bar', 5)
+ ··· o bar
+ ^^^
+
+ >>> test(' foo bar', 10, 'boo', 5)
+ ··· o bar
+ ^
+
+ """
+
+ s = line.lstrip()
+ column -= len(line) - len(s)
+ s = s.rstrip()
+
+ try:
+ i = s[column:].index(expression)
+ except ValueError:
+ # If we can't find the expression
+ # (this shouldn't happen), simply
+ # use a standard size marker
+ marker = "^"
+ else:
+ column += i
+ marker = "^" * len(expression)
+
+ if len(expression) > size:
+ offset = column
+ size = len(expression)
+ else:
+ window = (size - len(expression)) / 2.0
+ offset = column - window
+ offset -= min(3, max(0, column + window + len(expression) - len(s)))
+ offset = int(offset)
+
+ if offset > 0:
+ s = s[offset:]
+ r = s.lstrip()
+ d = len(s) - len(r)
+ s = "... " + r
+ column += 4 - d
+ column -= offset
+
+ # This also adds to the displayed length
+ size += 4
+
+ if len(s) > size:
+ s = s[:size].rstrip() + " ..."
+
+ return s, column * " " + marker
+
+
+def ellipsify(string, limit):
+ if len(string) > limit:
+ return "... " + string[-(limit - 4):]
+
+
+def reconstruct_exc(cls, state):
+ exc = Exception.__new__(cls)
+ exc.__dict__ = state
+ return exc
+
+
+class TemplateError(Exception):
+ """An error raised by Chameleon.
+
+ >>> from chameleon.tokenize import Token
+ >>> token = Token('token')
+ >>> message = 'message'
+
+ Make sure the exceptions can be copied:
+
+ >>> from copy import copy
+ >>> copy(TemplateError(message, token))
+ TemplateError('message', 'token')
+
+ And pickle/unpickled:
+
+ >>> from pickle import dumps, loads
+ >>> loads(dumps(TemplateError(message, token)))
+ TemplateError('message', 'token')
+
+ """
+
+ def __init__(self, msg, token):
+ if not isinstance(token, Token):
+ token = Token(token, 0)
+
+ self.msg = msg
+ self.token = safe_native(token)
+ self.offset = getattr(token, "pos", 0)
+ self.filename = token.filename
+
+ def __copy__(self):
+ inst = Exception.__new__(type(self))
+ inst.__dict__ = self.__dict__.copy()
+ return inst
+
+ def __reduce__(self):
+ return reconstruct_exc, (type(self), self.__dict__)
+
+ def __str__(self):
+ text = "%s\n\n" % self.msg
+ text += " - String: \"%s\"" % self.token
+
+ if self.filename:
+ text += "\n"
+ text += " - Filename: %s" % self.filename
+
+ try:
+ line, column = self.token.location
+ except AttributeError:
+ pass
+ else:
+ text += "\n"
+ text += " - Location: (%d:%d)" % (line, column)
+
+ return text
+
+ def __repr__(self):
+ try:
+ return "%s('%s', '%s')" % (
+ self.__class__.__name__, self.msg, self.token
+ )
+ except AttributeError:
+ return object.__repr__(self)
+
+
+class ParseError(TemplateError):
+ """An error occurred during parsing.
+
+ Indicates an error on the structural level.
+ """
+
+
+class CompilationError(TemplateError):
+ """An error occurred during compilation.
+
+ Indicates a general compilation error.
+ """
+
+
+class TranslationError(TemplateError):
+ """An error occurred during translation.
+
+ Indicates a general translation error.
+ """
+
+
+class LanguageError(CompilationError):
+ """Language syntax error.
+
+ Indicates a syntactical error due to incorrect usage of the
+ template language.
+ """
+
+
+class ExpressionError(LanguageError):
+ """An error occurred compiling an expression.
+
+ Indicates a syntactical error in an expression.
+ """
+
+
+class ExceptionFormatter(object):
+ def __init__(self, errors, econtext, rcontext):
+ kwargs = rcontext.copy()
+ kwargs.update(econtext)
+
+ for name in tuple(kwargs):
+ if name.startswith('__'):
+ del kwargs[name]
+
+ self._errors = errors
+ self._kwargs = kwargs
+
+ def __call__(self):
+ # Format keyword arguments; consecutive arguments are indented
+ # for readability
+ try:
+ formatted = format_kwargs(self._kwargs)
+ except:
+ # the ``pprint.pformat`` method calls the representation
+ # method of the arguments; this may fail and since we're
+ # already in an exception handler, there's no point in
+ # pursuing this further
+ formatted = ()
+
+ for index, string in enumerate(formatted[1:]):
+ formatted[index + 1] = " " * 15 + string
+
+ out = []
+ seen = set()
+
+ for error in reversed(self._errors):
+ expression, line, column, filename, exc = error
+
+ if exc in seen:
+ continue
+
+ seen.add(exc)
+
+ if isinstance(exc, UnicodeDecodeError):
+ string = safe_native(exc.object)
+
+ s, marker = compute_source_marker(
+ string, exc.start, string[exc.start:exc.end], LENGTH
+ )
+
+ out.append(" - Stream: %s" % s)
+ out.append(" %s" % marker)
+
+ _filename = ellipsify(filename, 60) if filename else "<string>"
+
+ out.append(" - Expression: \"%s\"" % expression)
+ out.append(" - Filename: %s" % _filename)
+ out.append(" - Location: (%d:%d)" % (line, column))
+
+ if filename and line and column:
+ try:
+ f = open(filename, 'r')
+ except IOError:
+ pass
+ else:
+ try:
+ # Pick out source line and format marker
+ for i, l in enumerate(f):
+ if i + 1 == line:
+ s, marker = compute_source_marker(
+ l, column, expression, LENGTH
+ )
+
+ out.append(" - Source: %s" % s)
+ out.append(" %s" % marker)
+ break
+ finally:
+ f.close()
+
+ out.append(" - Arguments: %s" % "\n".join(formatted))
+
+ formatted = traceback.format_exception_only(type(exc), exc)[-1]
+ formatted_class = "%s:" % type(exc).__name__
+
+ if formatted.startswith(formatted_class):
+ formatted = formatted[len(formatted_class):].lstrip()
+
+ return "\n".join(map(safe_native, [formatted] + out))
diff --git a/lib/Chameleon-2.9.2/src/chameleon/i18n.py b/lib/Chameleon-2.9.2/src/chameleon/i18n.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/i18n.py
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import re
+
+from .exc import CompilationError
+from .utils import unicode_string
+
+NAME_RE = r"[a-zA-Z][-a-zA-Z0-9_]*"
+
+WHITELIST = frozenset([
+ "translate",
+ "domain",
+ "target",
+ "source",
+ "attributes",
+ "data",
+ "name",
+ "mode",
+ "xmlns",
+ "xml"
+ ])
+
+_interp_regex = re.compile(r'(?<!\$)(\$(?:(%(n)s)|{(%(n)s)}))'
+ % ({'n': NAME_RE}))
+
+
+try: # pragma: no cover
+ str = unicode
+except NameError:
+ pass
+
+try: # pragma: no cover
+ # optional: `zope.i18n`, `zope.i18nmessageid`
+ from zope.i18n import interpolate
+ from zope.i18n import translate
+ from zope.i18nmessageid import Message
+except ImportError: # pragma: no cover
+
+ def fast_translate(msgid, domain=None, mapping=None, context=None,
+ target_language=None, default=None):
+ if default is None:
+ return msgid
+
+ if mapping:
+ def replace(match):
+ whole, param1, param2 = match.groups()
+ return unicode_string(mapping.get(param1 or param2, whole))
+ return _interp_regex.sub(replace, default)
+
+ return default
+else: # pragma: no cover
+ def fast_translate(msgid, domain=None, mapping=None, context=None,
+ target_language=None, default=None):
+ if msgid is None:
+ return
+
+ if target_language is not None or context is not None:
+ result = translate(
+ msgid, domain=domain, mapping=mapping, context=context,
+ target_language=target_language, default=default)
+ if result != msgid:
+ return result
+
+ if isinstance(msgid, Message):
+ default = msgid.default
+ mapping = msgid.mapping
+
+ if default is None:
+ default = str(msgid)
+
+ if not isinstance(default, basestring):
+ return default
+
+ return interpolate(default, mapping)
+
+
+def parse_attributes(attrs, xml=True):
+ d = {}
+
+ # filter out empty items, eg:
+ # i18n:attributes="value msgid; name msgid2;"
+ # would result in 3 items where the last one is empty
+ attrs = [spec for spec in attrs.split(";") if spec]
+
+ for spec in attrs:
+ if ',' in spec:
+ raise CompilationError(
+ "Attribute must not contain comma. Use semicolon to "
+ "list multiple attributes", spec
+ )
+ parts = spec.split()
+ if len(parts) == 2:
+ attr, msgid = parts
+ elif len(parts) == 1:
+ attr = parts[0]
+ msgid = None
+ else:
+ raise CompilationError(
+ "Illegal i18n:attributes specification.", spec)
+ if not xml:
+ attr = attr.lower()
+ attr = attr.strip()
+ if attr in d:
+ raise CompilationError(
+ "Attribute may only be specified once in i18n:attributes", attr)
+ d[attr] = msgid
+
+ return d
diff --git a/lib/Chameleon-2.9.2/src/chameleon/interfaces.py b/lib/Chameleon-2.9.2/src/chameleon/interfaces.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/interfaces.py
@@ -0,0 +1,102 @@
+from zope.interface import Interface
+from zope.interface import Attribute
+
+
+class ITALExpressionErrorInfo(Interface):
+
+ type = Attribute("type",
+ "The exception class.")
+
+ value = Attribute("value",
+ "The exception instance.")
+
+ lineno = Attribute("lineno",
+ "The line number the error occurred on in the source.")
+
+ offset = Attribute("offset",
+ "The character offset at which the error occurred.")
+
+
+class ITALIterator(Interface): # pragma: no cover
+ """A TAL iterator
+
+ Not to be confused with a Python iterator.
+ """
+
+ def next():
+ """Advance to the next value in the iteration, if possible
+
+ Return a true value if it was possible to advance and return
+ a false value otherwise.
+ """
+
+
+class ITALESIterator(ITALIterator): # pragma: no cover
+ """TAL Iterator provided by TALES
+
+ Values of this iterator are assigned to items in the repeat namespace.
+
+ For example, with a TAL statement like: tal:repeat="item items",
+ an iterator will be assigned to "repeat/item". The iterator
+ provides a number of handy methods useful in writing TAL loops.
+
+ The results are undefined of calling any of the methods except
+ 'length' before the first iteration.
+ """
+
+ def index():
+ """Return the position (starting with "0") within the iteration
+ """
+
+ def number():
+ """Return the position (starting with "1") within the iteration
+ """
+
+ def even():
+ """Return whether the current position is even
+ """
+
+ def odd():
+ """Return whether the current position is odd
+ """
+
+ def parity():
+ """Return 'odd' or 'even' depending on the position's parity
+
+ Useful for assigning CSS class names to table rows.
+ """
+
+ def start():
+ """Return whether the current position is the first position
+ """
+
+ def end():
+ """Return whether the current position is the last position
+ """
+
+ def letter():
+ """Return the position (starting with "a") within the iteration
+ """
+
+ def Letter():
+ """Return the position (starting with "A") within the iteration
+ """
+
+ def roman():
+ """Return the position (starting with "i") within the iteration
+ """
+
+ def Roman():
+ """Return the position (starting with "I") within the iteration
+ """
+
+ def item():
+ """Return the item at the current position
+ """
+
+ def length():
+ """Return the length of the sequence
+
+ Note that this may fail if the TAL iterator was created on a Python
+ iterator.
+ """
diff --git a/lib/Chameleon-2.9.2/src/chameleon/loader.py b/lib/Chameleon-2.9.2/src/chameleon/loader.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/loader.py
@@ -0,0 +1,174 @@
+import functools
+import imp
+import logging
+import os
+import py_compile
+import shutil
+import sys
+import tempfile
+import warnings
+
+import pkg_resources
+
+log = logging.getLogger('chameleon.loader')
+
+try:
+ str = unicode
+except NameError:
+ basestring = str
+
+
+def cache(func):
+ def load(self, *args, **kwargs):
+ template = self.registry.get(args)
+ if template is None:
+ self.registry[args] = template = func(self, *args, **kwargs)
+ return template
+ return load
+
+
+def abspath_from_asset_spec(spec):
+ pname, filename = spec.split(':', 1)
+ return pkg_resources.resource_filename(pname, filename)
+
+if os.name == "nt":
+ def abspath_from_asset_spec(spec, f=abspath_from_asset_spec):
+ if spec[1] == ":":
+ return spec
+ return f(spec)
+
+
+class TemplateLoader(object):
+ """Template loader class.
+
+ To load templates using relative filenames, pass a sequence of
+ paths (or a single path) as ``search_path``.
+
+ To apply a default filename extension to inputs which do not have
+ an extension already (i.e. no dot), provide this as
+ ``default_extension`` (e.g. ``'.pt'``).
+
+ Additional keyword-arguments will be passed on to the template
+ constructor.
+ """
+
+ default_extension = None
+
+ def __init__(self, search_path=None, default_extension=None, **kwargs):
+ if search_path is None:
+ search_path = []
+ if isinstance(search_path, basestring):
+ search_path = [search_path]
+ if default_extension is not None:
+ self.default_extension = ".%s" % default_extension.lstrip('.')
+ self.search_path = search_path
+ self.registry = {}
+ self.kwargs = kwargs
+
+ @cache
+ def load(self, spec, cls=None):
+ if cls is None:
+ raise ValueError("Unbound template loader.")
+
+ spec = spec.strip()
+
+ if self.default_extension is not None and '.' not in spec:
+ spec += self.default_extension
+
+ if ':' in spec:
+ spec = abspath_from_asset_spec(spec)
+
+ if os.path.isabs(spec):
+ return cls(spec, **self.kwargs)
+
+ for path in self.search_path:
+ path = os.path.join(path, spec)
+ if os.path.exists(path):
+ return cls(path, **self.kwargs)
+
+ raise ValueError("Template not found: %s." % spec)
+
+ def bind(self, cls):
+ return functools.partial(self.load, cls=cls)
+
+
+class MemoryLoader(object):
+ def build(self, source, filename):
+ code = compile(source, filename, 'exec')
+ env = {}
+ exec(code, env)
+ return env
+
+ def get(self, name):
+ return None
+
+
+class ModuleLoader(object):
+ def __init__(self, path, remove=False):
+ self.path = path
+ self.remove = remove
+
+ def __del__(self, shutil=shutil):
+ if not self.remove:
+ return
+ try:
+ shutil.rmtree(self.path)
+ except:
+ warnings.warn("Could not clean up temporary file path: %s" % (self.path,))
+
+ def get(self, filename):
+ path = os.path.join(self.path, filename)
+ if os.path.exists(path):
+ log.debug("loading module from cache: %s." % filename)
+ base, ext = os.path.splitext(filename)
+ return self._load(base, path)
+ else:
+ log.debug('cache miss: %s' % filename)
+
+ def build(self, source, filename):
+ imp.acquire_lock()
+ try:
+ d = self.get(filename)
+ if d is not None:
+ return d
+
+ base, ext = os.path.splitext(filename)
+ name = os.path.join(self.path, base + ".py")
+
+ log.debug("writing source to disk (%d bytes)." % len(source))
+ fd, fn = tempfile.mkstemp(prefix=base, suffix='.tmp', dir=self.path)
+ temp = os.fdopen(fd, 'w')
+
+ try:
+ try:
+ temp.write("%s\n" % '# -*- coding: utf-8 -*-')
+ temp.write(source)
+ finally:
+ temp.close()
+ except:
+ os.remove(fn)
+ raise
+
+ os.rename(fn, name)
+ log.debug("compiling %s into byte-code..." % filename)
+ py_compile.compile(name)
+
+ return self._load(base, name)
+ finally:
+ imp.release_lock()
+
+ def _load(self, base, filename):
+ imp.acquire_lock()
+ try:
+ module = sys.modules.get(base)
+ if module is None:
+ f = open(filename, 'rb')
+ try:
+ assert base not in sys.modules
+ module = imp.load_source(base, filename, f)
+ finally:
+ f.close()
+ finally:
+ imp.release_lock()
+
+ return module.__dict__
diff --git a/lib/Chameleon-2.9.2/src/chameleon/metal.py b/lib/Chameleon-2.9.2/src/chameleon/metal.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/metal.py
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+WHITELIST = frozenset([
+ "define-macro",
+ "extend-macro",
+ "use-macro",
+ "define-slot",
+ "fill-slot",
+ "xmlns",
+ "xml"
+ ])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/namespaces.py b/lib/Chameleon-2.9.2/src/chameleon/namespaces.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/namespaces.py
@@ -0,0 +1,9 @@
+XML_NS = "http://www.w3.org/XML/1998/namespace"
+XMLNS_NS = "http://www.w3.org/2000/xmlns/"
+XHTML_NS = "http://www.w3.org/1999/xhtml"
+TAL_NS = "http://xml.zope.org/namespaces/tal"
+META_NS = "http://xml.zope.org/namespaces/meta"
+METAL_NS = "http://xml.zope.org/namespaces/metal"
+XI_NS = "http://www.w3.org/2001/XInclude"
+I18N_NS = "http://xml.zope.org/namespaces/i18n"
+PY_NS = "http://genshi.edgewall.org/"
diff --git a/lib/Chameleon-2.9.2/src/chameleon/nodes.py b/lib/Chameleon-2.9.2/src/chameleon/nodes.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/nodes.py
@@ -0,0 +1,210 @@
+from .astutil import Node
+
+
+class UseExternalMacro(Node):
+ """Extend external macro."""
+
+ _fields = "expression", "slots", "extend"
+
+
+class Sequence(Node):
+ """Element sequence."""
+
+ _fields = "items",
+
+
+class Content(Node):
+ """Content substitution."""
+
+ _fields = "expression", "char_escape", "translate"
+
+
+class Default(Node):
+ """Represents a default value."""
+
+ _fields = "marker",
+
+
+class CodeBlock(Node):
+ _fields = "source",
+
+
+class Value(Node):
+ """Expression object value."""
+
+ _fields = "value",
+
+ def __repr__(self):
+ try:
+ line, column = self.value.location
+ except AttributeError:
+ line, column = 0, 0
+
+ return "<%s %r (%d:%d)>" % (
+ type(self).__name__, self.value, line, column
+ )
+
+
+class Substitution(Value):
+ """Expression value for text substitution."""
+
+ _fields = "value", "char_escape", "default"
+
+ default = None
+
+
+class Boolean(Value):
+ _fields = "value", "s"
+
+
+class Negate(Node):
+ """Wraps an expression with a negation."""
+
+ _fields = "value",
+
+
+class Element(Node):
+ """XML element."""
+
+ _fields = "start", "end", "content"
+
+
+class Attribute(Node):
+ """Element attribute."""
+
+ _fields = "name", "expression", "quote", "eq", "space"
+
+
+class Start(Node):
+ """Start-tag."""
+
+ _fields = "name", "prefix", "suffix", "attributes"
+
+
+class End(Node):
+ """End-tag."""
+
+ _fields = "name", "space", "prefix", "suffix"
+
+
+class Condition(Node):
+ """Node visited only if some condition holds."""
+
+ _fields = "expression", "node", "orelse"
+
+
+class Identity(Node):
+ """Condition expression that is true on identity."""
+
+ _fields = "expression", "value"
+
+
+class Equality(Node):
+ """Condition expression that is true on equality."""
+
+ _fields = "expression", "value"
+
+
+class Cache(Node):
+ """Cache (evaluate only once) the value of ``expression`` inside
+ ``node``.
+ """
+
+ _fields = "expressions", "node"
+
+
+class Assignment(Node):
+ """Variable assignment."""
+
+ _fields = "names", "expression", "local"
+
+
+class Alias(Assignment):
+ """Alias assignment.
+
+ Note that ``expression`` should be a cached or global value.
+ """
+
+ local = False
+
+
+class Define(Node):
+ """Variable definition in scope."""
+
+ _fields = "assignments", "node"
+
+
+class Repeat(Assignment):
+ """Iterate over provided assignment and repeat body."""
+
+ _fields = "names", "expression", "local", "whitespace", "node"
+
+
+class Macro(Node):
+ """Macro definition."""
+
+ _fields = "name", "body"
+
+
+class Program(Node):
+ _fields = "name", "body"
+
+
+class Module(Node):
+ _fields = "name", "program",
+
+
+class Context(Node):
+ _fields = "node",
+
+
+class Text(Node):
+ """Static text output."""
+
+ _fields = "value",
+
+
+class Interpolation(Text):
+ """String interpolation output."""
+
+ _fields = "value", "braces_required", "translation"
+
+
+class Translate(Node):
+ """Translate node."""
+
+ _fields = "msgid", "node"
+
+
+class Name(Node):
+ """Translation name."""
+
+ _fields = "name", "node"
+
+
+class Domain(Node):
+ """Update translation domain."""
+
+ _fields = "name", "node"
+
+
+class OnError(Node):
+ _fields = "fallback", "name", "node"
+
+
+class UseInternalMacro(Node):
+ """Use internal macro (defined inside same program)."""
+
+ _fields = "name",
+
+
+class FillSlot(Node):
+ """Fill a macro slot."""
+
+ _fields = "name", "node"
+
+
+class DefineSlot(Node):
+ """Define a macro slot."""
+
+ _fields = "name", "node"
diff --git a/lib/Chameleon-2.9.2/src/chameleon/parser.py b/lib/Chameleon-2.9.2/src/chameleon/parser.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/parser.py
@@ -0,0 +1,238 @@
+import re
+import logging
+
+try:
+ from collections import OrderedDict
+except ImportError:
+ from ordereddict import OrderedDict
+
+from .exc import ParseError
+from .namespaces import XML_NS
+from .tokenize import Token
+
+match_tag_prefix_and_name = re.compile(
+ r'^(?P<prefix></?)(?P<name>([^:\n ]+:)?[^ \n\t>/]+)'
+ '(?P<suffix>(?P<space>\s*)/?>)?',
+ re.UNICODE | re.DOTALL)
+match_single_attribute = re.compile(
+ r'(?P<space>\s+)(?!\d)'
+ r'(?P<name>[^ =/>\n\t]+)'
+ r'((?P<eq>\s*=\s*)'
+ r'((?P<quote>[\'"])(?P<value>.*?)(?P=quote)|'
+ r'(?P<alt_value>[^\s\'">/]+))|'
+ r'(?P<simple_value>(?![ \\n\\t\\r]*=)))',
+ re.UNICODE | re.DOTALL)
+match_comment = re.compile(
+ r'^<!--(?P<text>.*)-->$', re.DOTALL)
+match_cdata = re.compile(
+ r'^<!\[CDATA\[(?P<text>.*)\]>$', re.DOTALL)
+match_declaration = re.compile(
+ r'^<!(?P<text>[^>]+)>$', re.DOTALL)
+match_processing_instruction = re.compile(
+ r'^<\?(?P<name>\w+)(?P<text>.*?)\?>', re.DOTALL)
+match_xml_declaration = re.compile(r'^<\?xml(?=[ /])', re.DOTALL)
+
+log = logging.getLogger('chameleon.parser')
+
+
+def substitute(regex, repl, token):
+ if not isinstance(token, Token):
+ token = Token(token)
+
+ return Token(
+ regex.sub(repl, token),
+ token.pos,
+ token.source,
+ token.filename
+ )
+
+
+def groups(m, token):
+ result = []
+ for i, group in enumerate(m.groups()):
+ if group is not None:
+ j, k = m.span(i + 1)
+ group = token[j:k]
+
+ result.append(group)
+
+ return tuple(result)
+
+
+def groupdict(m, token):
+ d = m.groupdict()
+ for name, value in d.items():
+ if value is not None:
+ i, j = m.span(name)
+ d[name] = token[i:j]
+
+ return d
+
+
+def match_tag(token, regex=match_tag_prefix_and_name):
+ m = regex.match(token)
+ d = groupdict(m, token)
+
+ end = m.end()
+ token = token[end:]
+
+ attrs = d['attrs'] = []
+ for m in match_single_attribute.finditer(token):
+ attr = groupdict(m, token)
+ alt_value = attr.pop('alt_value', None)
+ if alt_value is not None:
+ attr['value'] = alt_value
+ attr['quote'] = ''
+ simple_value = attr.pop('simple_value', None)
+ if simple_value is not None:
+ attr['quote'] = ''
+ attr['value'] = ''
+ attr['eq'] = ''
+ attrs.append(attr)
+ d['suffix'] = token[m.end():]
+
+ return d
+
+
+def parse_tag(token, namespace):
+ node = match_tag(token)
+
+ update_namespace(node['attrs'], namespace)
+
+ if ':' in node['name']:
+ prefix = node['name'].split(':')[0]
+ else:
+ prefix = None
+
+ default = node['namespace'] = namespace.get(prefix, XML_NS)
+
+ node['ns_attrs'] = unpack_attributes(
+ node['attrs'], namespace, default)
+
+ return node
+
+
+def update_namespace(attributes, namespace):
+ # possibly update namespaces; we do this in a separate step
+ # because this assignment is irrespective of order
+ for attribute in attributes:
+ name = attribute['name']
+ value = attribute['value']
+ if name == 'xmlns':
+ namespace[None] = value
+ elif name.startswith('xmlns:'):
+ namespace[name[6:]] = value
+
+
+def unpack_attributes(attributes, namespace, default):
+ namespaced = OrderedDict()
+
+ for index, attribute in enumerate(attributes):
+ name = attribute['name']
+ value = attribute['value']
+
+ if ':' in name:
+ prefix = name.split(':')[0]
+ name = name[len(prefix) + 1:]
+ try:
+ ns = namespace[prefix]
+ except KeyError:
+ raise KeyError(
+ "Undefined namespace prefix: %s." % prefix)
+ else:
+ ns = default
+ namespaced[ns, name] = value
+
+ return namespaced
+
+
+def identify(string):
+ if string.startswith("<"):
+ if string.startswith("<!--"):
+ return "comment"
+ if string.startswith("<![CDATA["):
+ return "cdata"
+ if string.startswith("<!"):
+ return "declaration"
+ if string.startswith("<?xml"):
+ return "xml_declaration"
+ if string.startswith("<?"):
+ return "processing_instruction"
+ if string.startswith("</"):
+ return "end_tag"
+ if string.endswith("/>"):
+ return "empty_tag"
+ if string.endswith(">"):
+ return "start_tag"
+ return "error"
+ return "text"
+
+
+class ElementParser(object):
+ """Parses tokens into elements."""
+
+ def __init__(self, stream, default_namespaces):
+ self.stream = stream
+ self.queue = []
+ self.index = []
+ self.namespaces = [default_namespaces.copy()]
+
+ def __iter__(self):
+ for token in self.stream:
+ item = self.parse(token)
+ self.queue.append(item)
+
+ return iter(self.queue)
+
+ def parse(self, token):
+ kind = identify(token)
+ visitor = getattr(self, "visit_%s" % kind, self.visit_default)
+ return visitor(kind, token)
+
+ def visit_comment(self, kind, token):
+ return "comment", (token, )
+
+ def visit_cdata(self, kind, token):
+ return "cdata", (token, )
+
+ def visit_default(self, kind, token):
+ return "default", (token, )
+
+ def visit_processing_instruction(self, kind, token):
+ m = match_processing_instruction.match(token)
+ return "processing_instruction", (groupdict(m, token), )
+
+ def visit_text(self, kind, token):
+ return kind, (token, )
+
+ def visit_start_tag(self, kind, token):
+ namespace = self.namespaces[-1].copy()
+ self.namespaces.append(namespace)
+ node = parse_tag(token, namespace)
+ self.index.append((node['name'], len(self.queue)))
+ return kind, (node, )
+
+ def visit_end_tag(self, kind, token):
+ try:
+ namespace = self.namespaces.pop()
+ except IndexError:
+ raise ParseError("Unexpected end tag.", token)
+
+ node = parse_tag(token, namespace)
+
+ while self.index:
+ name, pos = self.index.pop()
+ if name == node['name']:
+ start, = self.queue.pop(pos)[1]
+ children = self.queue[pos:]
+ del self.queue[pos:]
+ break
+ else:
+ raise ParseError("Unexpected end tag.", token)
+
+ return "element", (start, node, children)
+
+ def visit_empty_tag(self, kind, token):
+ namespace = self.namespaces[-1].copy()
+ node = parse_tag(token, namespace)
+ return "element", (node, None, [])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/program.py b/lib/Chameleon-2.9.2/src/chameleon/program.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/program.py
@@ -0,0 +1,38 @@
+try:
+ str = unicode
+except NameError:
+ long = int
+
+from .tokenize import iter_xml
+from .tokenize import iter_text
+from .parser import ElementParser
+from .namespaces import XML_NS
+from .namespaces import XMLNS_NS
+
+
+class ElementProgram(object):
+ DEFAULT_NAMESPACES = {
+ 'xmlns': XMLNS_NS,
+ 'xml': XML_NS,
+ }
+
+ tokenizers = {
+ 'xml': iter_xml,
+ 'text': iter_text,
+ }
+
+ def __init__(self, source, mode="xml", filename=None):
+ tokenizer = self.tokenizers[mode]
+ tokens = tokenizer(source, filename)
+ parser = ElementParser(tokens, self.DEFAULT_NAMESPACES)
+
+ self.body = []
+
+ for kind, args in parser:
+ node = self.visit(kind, args)
+ if node is not None:
+ self.body.append(node)
+
+ def visit(self, kind, args):
+ visitor = getattr(self, "visit_%s" % kind)
+ return visitor(*args)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/py25.py b/lib/Chameleon-2.9.2/src/chameleon/py25.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/py25.py
@@ -0,0 +1,36 @@
+import sys
+
+def lookup_attr(obj, key):
+ try:
+ return getattr(obj, key)
+ except AttributeError:
+ exc = sys.exc_info()[1]
+ try:
+ get = obj.__getitem__
+ except AttributeError:
+ raise exc
+ try:
+ return get(key)
+ except KeyError:
+ raise exc
+
+def exec_(code, globs=None, locs=None):
+ """Execute code in a namespace."""
+ if globs is None:
+ frame = sys._getframe(1)
+ globs = frame.f_globals
+ if locs is None:
+ locs = frame.f_locals
+ del frame
+ elif locs is None:
+ locs = globs
+ exec("""exec code in globs, locs""")
+
+
+exec_("""def raise_with_traceback(exc, tb):
+ raise type(exc), exc, tb
+""")
+
+
+def next(iter):
+ return iter.next()
diff --git a/lib/Chameleon-2.9.2/src/chameleon/py26.py b/lib/Chameleon-2.9.2/src/chameleon/py26.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/py26.py
@@ -0,0 +1,15 @@
+import sys
+
+def lookup_attr(obj, key):
+ try:
+ return getattr(obj, key)
+ except AttributeError:
+ exc = sys.exc_info()[1]
+ try:
+ get = obj.__getitem__
+ except AttributeError:
+ raise exc
+ try:
+ return get(key)
+ except KeyError:
+ raise exc
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tal.py b/lib/Chameleon-2.9.2/src/chameleon/tal.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tal.py
@@ -0,0 +1,479 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import re
+import copy
+
+from .exc import LanguageError
+from .utils import descriptorint
+from .utils import descriptorstr
+from .namespaces import XMLNS_NS
+from .parser import groups
+
+
+try:
+ next
+except NameError:
+ from chameleon.py25 import next
+
+try:
+ # optional library: `zope.interface`
+ import interfaces
+ import zope.interface
+except ImportError:
+ interfaces = None
+
+
+NAME = r"[a-zA-Z_][-a-zA-Z0-9_]*"
+DEFINE_RE = re.compile(r"(?s)\s*(?:(global|local)\s+)?" +
+ r"(%s|\(%s(?:,\s*%s)*\))\s+(.*)\Z" % (NAME, NAME, NAME),
+ re.UNICODE)
+SUBST_RE = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S | re.UNICODE)
+ATTR_RE = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S | re.UNICODE)
+
+ENTITY_RE = re.compile(r'(&(#?)(x?)(\d{1,5}|\w{1,8});)')
+
+WHITELIST = frozenset([
+ "define",
+ "comment",
+ "condition",
+ "content",
+ "replace",
+ "repeat",
+ "attributes",
+ "on-error",
+ "omit-tag",
+ "script",
+ "switch",
+ "case",
+ "xmlns",
+ "xml"
+ ])
+
+
+def split_parts(arg):
+ # Break in pieces at undoubled semicolons and
+ # change double semicolons to singles:
+ i = 0
+ while i < len(arg):
+ m = ENTITY_RE.search(arg[i:])
+ if m is None:
+ break
+ arg = arg[:i + m.end()] + ';' + arg[i + m.end():]
+ i += m.end()
+
+ arg = arg.replace(";;", "\0")
+ parts = arg.split(';')
+ parts = [p.replace("\0", ";") for p in parts]
+ if len(parts) > 1 and not parts[-1].strip():
+ del parts[-1] # It ended in a semicolon
+
+ return parts
+
+
+def parse_attributes(clause):
+ attrs = {}
+ for part in split_parts(clause):
+ m = ATTR_RE.match(part)
+ if not m:
+ raise LanguageError(
+ "Bad syntax in attributes.", clause)
+ name, expr = groups(m, part)
+ if name in attrs:
+ raise LanguageError(
+ "Duplicate attribute name in attributes.", part)
+
+ attrs[name] = expr
+
+ return attrs
+
+
+def parse_substitution(clause):
+ m = SUBST_RE.match(clause)
+ if m is None:
+ raise LanguageError(
+ "Invalid content substitution syntax.", clause)
+
+ key, expression = groups(m, clause)
+ if not key:
+ key = "text"
+
+ return key, expression
+
+
+def parse_defines(clause):
+ """
+ Parses a tal:define value.
+
+ # Basic syntax, implicit local
+ >>> parse_defines('hello lovely')
+ [('local', ('hello',), 'lovely')]
+
+ # Explicit local
+ >>> parse_defines('local hello lovely')
+ [('local', ('hello',), 'lovely')]
+
+ # With global
+ >>> parse_defines('global hello lovely')
+ [('global', ('hello',), 'lovely')]
+
+ # Multiple expressions
+ >>> parse_defines('hello lovely; tea time')
+ [('local', ('hello',), 'lovely'), ('local', ('tea',), 'time')]
+
+ # With multiple names
+ >>> parse_defines('(hello, howdy) lovely')
+ [('local', ['hello', 'howdy'], 'lovely')]
+
+ # With unicode whitespace
+ >>> try:
+ ... s = '\xc2\xa0hello lovely'.decode('utf-8')
+ ... except AttributeError:
+ ... s = '\xa0hello lovely'
+ >>> from chameleon.utils import unicode_string
+ >>> parse_defines(s) == [
+ ... ('local', ('hello',), 'lovely')
+ ... ]
+ True
+
+ """
+ defines = []
+ for part in split_parts(clause):
+ m = DEFINE_RE.match(part)
+ if m is None:
+ raise LanguageError("Invalid define syntax", part)
+ context, name, expr = groups(m, part)
+ context = context or "local"
+
+ if name.startswith('('):
+ names = [n.strip() for n in name.strip('()').split(',')]
+ else:
+ names = (name,)
+
+ defines.append((context, names, expr))
+
+ return defines
+
+
+def prepare_attributes(attrs, dyn_attributes, i18n_attributes,
+ ns_attributes, drop_ns):
+ drop = set([attribute['name'] for attribute, (ns, value)
+ in zip(attrs, ns_attributes)
+ if ns in drop_ns or (
+ ns == XMLNS_NS and
+ attribute['value'] in drop_ns
+ )
+ ])
+
+ attributes = []
+ normalized = {}
+
+ for attribute in attrs:
+ name = attribute['name']
+
+ if name in drop:
+ continue
+
+ attributes.append((
+ name,
+ attribute['value'],
+ attribute['quote'],
+ attribute['space'],
+ attribute['eq'],
+ None,
+ ))
+
+ normalized[name.lower()] = len(attributes) - 1
+
+ for name, expr in dyn_attributes.items():
+ index = normalized.get(name.lower())
+ if index is not None:
+ _, text, quote, space, eq, _ = attributes[index]
+ add = attributes.__setitem__
+ else:
+ text = None
+ quote = '"'
+ space = " "
+ eq = "="
+ index = len(attributes)
+ add = attributes.insert
+ normalized[name.lower()] = len(attributes) - 1
+
+ attribute = name, text, quote, space, eq, expr
+ add(index, attribute)
+
+ for name in i18n_attributes:
+ attr = name.lower()
+ if attr not in normalized:
+ attributes.append((name, name, '"', " ", "=", None))
+ normalized[attr] = len(attributes) - 1
+
+ return attributes
+
+
+class RepeatItem(object):
+ __slots__ = "length", "_iterator"
+
+ __allow_access_to_unprotected_subobjects__ = True
+
+ def __init__(self, iterator, length):
+ self.length = length
+ self._iterator = iterator
+
+ def __iter__(self):
+ return self._iterator
+
+ try:
+ iter(()).__len__
+ except AttributeError:
+ @descriptorint
+ def index(self):
+ try:
+ remaining = self._iterator.__length_hint__()
+ except AttributeError:
+ remaining = len(tuple(copy.copy(self._iterator)))
+ return self.length - remaining - 1
+ else:
+ @descriptorint
+ def index(self):
+ remaining = self._iterator.__len__()
+ return self.length - remaining - 1
+
+ @descriptorint
+ def start(self):
+ return self.index == 0
+
+ @descriptorint
+ def end(self):
+ return self.index == self.length - 1
+
+ @descriptorint
+ def number(self):
+ return self.index + 1
+
+ @descriptorstr
+ def odd(self):
+ """Returns a true value if the item index is odd.
+
+ >>> it = RepeatItem(iter(("apple", "pear")), 2)
+
+ >>> next(it._iterator)
+ 'apple'
+ >>> it.odd()
+ ''
+
+ >>> next(it._iterator)
+ 'pear'
+ >>> it.odd()
+ 'odd'
+ """
+
+ return self.index % 2 == 1 and 'odd' or ''
+
+ @descriptorstr
+ def even(self):
+ """Returns a true value if the item index is even.
+
+ >>> it = RepeatItem(iter(("apple", "pear")), 2)
+
+ >>> next(it._iterator)
+ 'apple'
+ >>> it.even()
+ 'even'
+
+ >>> next(it._iterator)
+ 'pear'
+ >>> it.even()
+ ''
+ """
+
+ return self.index % 2 == 0 and 'even' or ''
+
+ def next(self):
+ raise NotImplementedError(
+ "Method not implemented (can't update local variable).")
+
+ def _letter(self, base=ord('a'), radix=26):
+ """Get the iterator position as a lower-case letter
+
+ >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+ >>> next(it._iterator)
+ 'apple'
+ >>> it.letter()
+ 'a'
+ >>> next(it._iterator)
+ 'pear'
+ >>> it.letter()
+ 'b'
+ >>> next(it._iterator)
+ 'orange'
+ >>> it.letter()
+ 'c'
+ """
+
+ index = self.index
+ if index < 0:
+ raise TypeError("No iteration position")
+ s = ""
+ while 1:
+ index, off = divmod(index, radix)
+ s = chr(base + off) + s
+ if not index:
+ return s
+
+ letter = descriptorstr(_letter)
+
+ @descriptorstr
+ def Letter(self):
+ """Get the iterator position as an upper-case letter
+
+ >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+ >>> next(it._iterator)
+ 'apple'
+ >>> it.Letter()
+ 'A'
+ >>> next(it._iterator)
+ 'pear'
+ >>> it.Letter()
+ 'B'
+ >>> next(it._iterator)
+ 'orange'
+ >>> it.Letter()
+ 'C'
+ """
+
+ return self._letter(base=ord('A'))
+
+ @descriptorstr
+ def Roman(self, rnvalues=(
+ (1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'),
+ (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'),
+ (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I'))):
+ """Get the iterator position as an upper-case roman numeral
+
+ >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+ >>> next(it._iterator)
+ 'apple'
+ >>> it.Roman()
+ 'I'
+ >>> next(it._iterator)
+ 'pear'
+ >>> it.Roman()
+ 'II'
+ >>> next(it._iterator)
+ 'orange'
+ >>> it.Roman()
+ 'III'
+ """
+
+ n = self.index + 1
+ s = ""
+ for v, r in rnvalues:
+ rct, n = divmod(n, v)
+ s = s + r * rct
+ return s
+
+ @descriptorstr
+ def roman(self):
+ """Get the iterator position as a lower-case roman numeral
+
+ >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+ >>> next(it._iterator)
+ 'apple'
+ >>> it.roman()
+ 'i'
+ >>> next(it._iterator)
+ 'pear'
+ >>> it.roman()
+ 'ii'
+ >>> next(it._iterator)
+ 'orange'
+ >>> it.roman()
+ 'iii'
+ """
+
+ return self.Roman().lower()
+
+
+if interfaces is not None:
+ zope.interface.classImplements(RepeatItem, interfaces.ITALESIterator)
+
+
+class RepeatDict(dict):
+ """Repeat dictionary implementation.
+
+ >>> repeat = RepeatDict({})
+ >>> iterator, length = repeat('numbers', range(5))
+ >>> length
+ 5
+
+ >>> repeat['numbers']
+ <chameleon.tal.RepeatItem object at ...>
+
+ """
+
+ __slots__ = "__setitem__", "__getitem__", "__getattr__"
+
+ def __init__(self, d):
+ self.__setitem__ = d.__setitem__
+ self.__getitem__ = d.__getitem__
+ self.__getattr__ = d.__getitem__
+
+ def __call__(self, key, iterable):
+ """We coerce the iterable to a tuple and return an iterator
+ after registering it in the repeat dictionary."""
+
+ try:
+ iterable = tuple(iterable)
+ except TypeError:
+ if iterable is None:
+ iterable = ()
+ else:
+ # The message below to the TypeError is the Python
+ # 2.5-style exception message. Python 2.4.X also
+ # raises a TypeError, but with a different message.
+ # ("TypeError: iteration over non-sequence"). The
+ # Python 2.5 error message is more helpful. We
+ # construct the 2.5-style message explicitly here so
+ # that both Python 2.4.X and Python 2.5+ will raise
+ # the same error. This makes writing the tests eaiser
+ # and makes the output easier to understand.
+ raise TypeError("%r object is not iterable" %
+ type(iterable).__name__)
+
+ length = len(iterable)
+ iterator = iter(iterable)
+
+ # Insert as repeat item
+ self[key] = RepeatItem(iterator, length)
+
+ return iterator, length
+
+
+class ErrorInfo(object):
+ """Information about an exception passed to an on-error handler."""
+
+ def __init__(self, err, position=(None, None)):
+ if isinstance(err, Exception):
+ self.type = err.__class__
+ self.value = err
+ else:
+ self.type = err
+ self.value = None
+ self.lineno = position[0]
+ self.offset = position[1]
+
+
+if interfaces is not None:
+ zope.interface.classImplements(ErrorInfo, interfaces.ITALExpressionErrorInfo)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tales.py b/lib/Chameleon-2.9.2/src/chameleon/tales.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tales.py
@@ -0,0 +1,541 @@
+import re
+import sys
+
+from .astutil import parse
+from .astutil import store
+from .astutil import load
+from .astutil import ItemLookupOnAttributeErrorVisitor
+from .codegen import TemplateCodeGenerator
+from .codegen import template
+from .codegen import reverse_builtin_map
+from .astutil import Builtin
+from .astutil import Symbol
+from .exc import ExpressionError
+from .utils import resolve_dotted
+from .utils import Markup
+from .utils import ast
+from .tokenize import Token
+from .parser import substitute
+from .compiler import Interpolator
+
+try:
+ from .py26 import lookup_attr
+except SyntaxError:
+ from .py25 import lookup_attr
+
+
+split_parts = re.compile(r'(?<!\\)\|')
+match_prefix = re.compile(r'^\s*([a-z\-_]+):').match
+re_continuation = re.compile(r'\\\s*$', re.MULTILINE)
+
+try:
+ from __builtin__ import basestring
+except ImportError:
+ basestring = str
+
+
+def resolve_global(value):
+ name = reverse_builtin_map.get(value)
+ if name is not None:
+ return Builtin(name)
+
+ return Symbol(value)
+
+
+def test(expression, engine=None, **env):
+ if engine is None:
+ engine = SimpleEngine()
+
+ body = expression(store("result"), engine)
+ module = ast.Module(body)
+ module = ast.fix_missing_locations(module)
+ env['rcontext'] = {}
+ source = TemplateCodeGenerator(module).code
+ code = compile(source, '<string>', 'exec')
+ exec(code, env)
+ result = env["result"]
+
+ if isinstance(result, basestring):
+ result = str(result)
+
+ return result
+
+
+def transform_attribute(node):
+ return template(
+ "lookup(object, name)",
+ lookup=Symbol(lookup_attr),
+ object=node.value,
+ name=ast.Str(s=node.attr),
+ mode="eval"
+ )
+
+
+class TalesExpr(object):
+ """Base class.
+
+ This class helps implementations for the Template Attribute
+ Language Expression Syntax (TALES).
+
+ The syntax evaluates one or more expressions, separated by '|'
+ (pipe). The first expression that succeeds, is returned.
+
+ Expression:
+
+ expression := (type ':')? line ('|' expression)?
+ line := .*
+
+ Expression lines may not contain the pipe character unless
+ escaped. It has a special meaning:
+
+ If the expression to the left of the pipe fails (raises one of the
+ exceptions listed in ``catch_exceptions``), evaluation proceeds to
+ the expression(s) on the right.
+
+ Subclasses must implement ``translate`` which assigns a value for
+ a given expression.
+
+ >>> class PythonPipeExpr(TalesExpr):
+ ... def translate(self, expression, target):
+ ... compiler = PythonExpr(expression)
+ ... return compiler(target, None)
+
+ >>> test(PythonPipeExpr('foo | bar | 42'))
+ 42
+
+ >>> test(PythonPipeExpr('foo|42'))
+ 42
+ """
+
+ exceptions = NameError, \
+ ValueError, \
+ AttributeError, \
+ LookupError, \
+ TypeError
+
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ remaining = self.expression
+ assignments = []
+
+ while remaining:
+ if match_prefix(remaining) is not None:
+ compiler = engine.parse(remaining)
+ assignment = compiler.assign_value(target)
+ remaining = ""
+ else:
+ for m in split_parts.finditer(remaining):
+ expression = remaining[:m.start()]
+ remaining = remaining[m.end():]
+ break
+ else:
+ expression = remaining
+ remaining = ""
+
+ expression = expression.replace('\\|', '|')
+ assignment = self.translate(expression, target)
+ assignments.append(assignment)
+
+ if not assignments:
+ assignments.append(
+ self.translate(remaining, target)
+ )
+
+ for i, assignment in enumerate(reversed(assignments)):
+ if i == 0:
+ body = assignment
+ else:
+ body = [ast.TryExcept(
+ body=assignment,
+ handlers=[ast.ExceptHandler(
+ type=ast.Tuple(
+ elts=map(resolve_global, self.exceptions),
+ ctx=ast.Load()),
+ name=None,
+ body=body,
+ )],
+ )]
+
+ return body
+
+ def translate(self, expression, target):
+ """Return statements that assign a value to ``target``."""
+
+ raise NotImplementedError(
+ "Must be implemented by a subclass.")
+
+
+class PathExpr(TalesExpr):
+ """Path expression compiler.
+
+ Syntax::
+
+ PathExpr ::= Path [ '|' Path ]*
+ Path ::= variable [ '/' URL_Segment ]*
+ variable ::= Name
+
+ For example::
+
+ request/cookies/oatmeal
+ nothing
+ here/some-file 2001_02.html.tar.gz/foo
+ root/to/branch | default
+
+ When a path expression is evaluated, it attempts to traverse
+ each path, from left to right, until it succeeds or runs out of
+ paths. To traverse a path, it first fetches the object stored in
+ the variable. For each path segment, it traverses from the current
+ object to the subobject named by the path segment.
+
+ Once a path has been successfully traversed, the resulting object
+ is the value of the expression. If it is a callable object, such
+ as a method or class, it is called.
+
+ The semantics of traversal (and what it means to be callable) are
+ implementation-dependent (see the ``translate`` method).
+ """
+
+ def translate(self, expression, target):
+ raise NotImplementedError(
+ "Path expressions are not yet implemented. "
+ "It's unclear whether a general implementation "
+ "can be devised.")
+
+
+class PythonExpr(TalesExpr):
+ """Python expression compiler.
+
+ >>> test(PythonExpr('2 + 2'))
+ 4
+
+ The Python expression is a TALES expression. That means we can use
+ the pipe operator:
+
+ >>> test(PythonExpr('foo | 2 + 2 | 5'))
+ 4
+
+ To include a pipe character, use a backslash escape sequence:
+
+ >>> test(PythonExpr('\"\|\"'))
+ '|'
+ """
+
+ transform = ItemLookupOnAttributeErrorVisitor(transform_attribute)
+
+ def parse(self, string):
+ return parse(string, 'eval').body
+
+ def translate(self, expression, target):
+ # Strip spaces
+ string = expression.strip()
+
+ # Conver line continuations to newlines
+ string = substitute(re_continuation, '\n', string)
+
+ # Convert newlines to spaces
+ string = string.replace('\n', ' ')
+
+ try:
+ value = self.parse(string)
+ except SyntaxError:
+ exc = sys.exc_info()[1]
+ raise ExpressionError(exc.msg, string)
+
+ # Transform attribute lookups to allow fallback to item lookup
+ self.transform.visit(value)
+
+ return [ast.Assign(targets=[target], value=value)]
+
+
+class ImportExpr(object):
+ re_dotted = re.compile(r'^[A-Za-z.]+$')
+
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ string = self.expression.strip().replace('\n', ' ')
+ value = template(
+ "RESOLVE(NAME)",
+ RESOLVE=Symbol(resolve_dotted),
+ NAME=ast.Str(s=string),
+ mode="eval",
+ )
+ return [ast.Assign(targets=[target], value=value)]
+
+
+class NotExpr(object):
+ """Negates the expression.
+
+ >>> engine = SimpleEngine(PythonExpr)
+
+ >>> test(NotExpr('False'), engine)
+ True
+ >>> test(NotExpr('True'), engine)
+ False
+ """
+
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ compiler = engine.parse(self.expression)
+ body = compiler.assign_value(target)
+ return body + template("target = not target", target=target)
+
+
+class StructureExpr(object):
+ """Wraps the expression result as 'structure'.
+
+ >>> engine = SimpleEngine(PythonExpr)
+
+ >>> test(StructureExpr('\"<tt>foo</tt>\"'), engine)
+ '<tt>foo</tt>'
+ """
+
+ wrapper_class = Symbol(Markup)
+
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ compiler = engine.parse(self.expression)
+ body = compiler.assign_value(target)
+ return body + template(
+ "target = wrapper(target)",
+ target=target,
+ wrapper=self.wrapper_class
+ )
+
+
+class IdentityExpr(object):
+ """Identity expression.
+
+ Exists to demonstrate the interface.
+
+ >>> test(IdentityExpr('42'))
+ 42
+ """
+
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ compiler = engine.parse(self.expression)
+ return compiler.assign_value(target)
+
+
+class StringExpr(object):
+ """Similar to the built-in ``string.Template``, but uses an
+ expression engine to support pluggable string substitution
+ expressions.
+
+ Expr string:
+
+ string := (text | substitution) (string)?
+ substitution := ('$' variable | '${' expression '}')
+ text := .*
+
+ In other words, an expression string can contain multiple
+ substitutions. The text- and substitution parts will be
+ concatenated back into a string.
+
+ >>> test(StringExpr('Hello ${name}!'), name='world')
+ 'Hello world!'
+
+ In the default configuration, braces may be omitted if the
+ expression is an identifier.
+
+ >>> test(StringExpr('Hello $name!'), name='world')
+ 'Hello world!'
+
+ The ``braces_required`` flag changes this setting:
+
+ >>> test(StringExpr('Hello $name!', True))
+ 'Hello $name!'
+
+ We can escape interpolation using the standard escaping
+ syntax:
+
+ >>> test(StringExpr('\\${name}'))
+ '\\\${name}'
+
+ Multiple interpolations in one:
+
+ >>> test(StringExpr(\"Hello ${'a'}${'b'}${'c'}!\"))
+ 'Hello abc!'
+
+ Here's a more involved example taken from a javascript source:
+
+ >>> result = test(StringExpr(\"\"\"
+ ... function(oid) {
+ ... $('#' + oid).autocomplete({source: ${'source'}});
+ ... }
+ ... \"\"\"))
+
+ >>> 'source: source' in result
+ True
+
+ In the above examples, the expression is evaluated using the
+ dummy engine which just returns the input as a string.
+
+ As an example, we'll implement an expression engine which
+ instead counts the number of characters in the expresion and
+ returns an integer result.
+
+ >>> class engine:
+ ... @staticmethod
+ ... def parse(expression):
+ ... class compiler:
+ ... @staticmethod
+ ... def assign_text(target):
+ ... return [
+ ... ast.Assign(
+ ... targets=[target],
+ ... value=ast.Num(n=len(expression))
+ ... )]
+ ...
+ ... return compiler
+
+ This will demonstrate how the string expression coerces the
+ input to a string.
+
+ >>> expr = StringExpr(
+ ... 'There are ${hello world} characters in \"hello world\"')
+
+ We evaluate the expression using the new engine:
+
+ >>> test(expr, engine)
+ 'There are 11 characters in \"hello world\"'
+ """
+
+ def __init__(self, expression, braces_required=False):
+ # The code relies on the expression being a token string
+ if not isinstance(expression, Token):
+ expression = Token(expression, 0)
+
+ self.translator = Interpolator(expression, braces_required)
+
+ def __call__(self, name, engine):
+ return self.translator(name, engine)
+
+
+class ProxyExpr(StringExpr):
+ def __init__(self, name, *args):
+ super(ProxyExpr, self).__init__(*args)
+ self.name = name
+
+ def __call__(self, target, engine):
+ assignment = super(ProxyExpr, self).__call__(target, engine)
+ return assignment + [
+ ast.Assign(targets=[target], value=ast.Call(
+ func=load(self.name),
+ args=[target],
+ keywords=[],
+ starargs=None,
+ kwargs=None
+ ))
+ ]
+
+
+class ExistsExpr(object):
+ """Boolean wrapper.
+
+ Return 0 if the expression results in an exception, otherwise 1.
+
+ As a means to generate exceptions, we set up an expression engine
+ which evaluates the provided expression using Python:
+
+ >>> engine = SimpleEngine(PythonExpr)
+
+ >>> test(ExistsExpr('int(0)'), engine)
+ 1
+ >>> test(ExistsExpr('int(None)'), engine)
+ 0
+
+ """
+
+ exceptions = AttributeError, LookupError, TypeError, NameError, KeyError
+
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ ignore = store("_ignore")
+ compiler = engine.parse(self.expression)
+ body = compiler.assign_value(ignore)
+
+ classes = map(resolve_global, self.exceptions)
+
+ return [
+ ast.TryExcept(
+ body=body,
+ handlers=[ast.ExceptHandler(
+ type=ast.Tuple(elts=classes, ctx=ast.Load()),
+ name=None,
+ body=template("target = 0", target=target),
+ )],
+ orelse=template("target = 1", target=target)
+ )
+ ]
+
+
+class ExpressionParser(object):
+ def __init__(self, factories, default):
+ self.factories = factories
+ self.default = default
+
+ def __call__(self, expression):
+ m = match_prefix(expression)
+ if m is not None:
+ prefix = m.group(1)
+ expression = expression[m.end():]
+ else:
+ prefix = self.default
+
+ try:
+ factory = self.factories[prefix]
+ except KeyError:
+ exc = sys.exc_info()[1]
+ raise LookupError(
+ "Unknown expression type: %s." % str(exc)
+ )
+
+ return factory(expression)
+
+
+class SimpleEngine(object):
+ expression = PythonExpr
+
+ def __init__(self, expression=None):
+ if expression is not None:
+ self.expression = expression
+
+ def parse(self, string):
+ compiler = self.expression(string)
+ return SimpleCompiler(compiler, self)
+
+
+class SimpleCompiler(object):
+ def __init__(self, compiler, engine):
+ self.compiler = compiler
+ self.engine = engine
+
+ def assign_text(self, target):
+ """Assign expression string as a text value."""
+
+ return self._assign_value_and_coerce(target, "str")
+
+ def assign_value(self, target):
+ """Assign expression string as object value."""
+
+ return self.compiler(target, self.engine)
+
+ def _assign_value_and_coerce(self, target, builtin):
+ return self.assign_value(target) + template(
+ "target = builtin(target)",
+ target=target,
+ builtin=builtin
+ )
diff --git a/lib/Chameleon-2.9.2/src/chameleon/template.py b/lib/Chameleon-2.9.2/src/chameleon/template.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/template.py
@@ -0,0 +1,332 @@
+from __future__ import with_statement
+
+import os
+import sys
+import copy
+import hashlib
+import shutil
+import logging
+import tempfile
+import inspect
+
+pkg_digest = hashlib.sha1(__name__.encode('utf-8'))
+
+try:
+ import pkg_resources
+except ImportError:
+ logging.info("Setuptools not installed. Unable to determine version.")
+else:
+ for path in sys.path:
+ for distribution in pkg_resources.find_distributions(path):
+ if distribution.has_version():
+ version = distribution.version.encode('utf-8')
+ pkg_digest.update(version)
+
+
+from .exc import TemplateError
+from .exc import ExceptionFormatter
+from .compiler import Compiler
+from .config import DEBUG_MODE
+from .config import AUTO_RELOAD
+from .config import EAGER_PARSING
+from .config import CACHE_DIRECTORY
+from .loader import ModuleLoader
+from .loader import MemoryLoader
+from .nodes import Module
+from .utils import DebuggingOutputStream
+from .utils import Scope
+from .utils import join
+from .utils import mangle
+from .utils import create_formatted_exception
+from .utils import read_bytes
+from .utils import raise_with_traceback
+from .utils import byte_string
+
+
+log = logging.getLogger('chameleon.template')
+
+
+def _make_module_loader():
+ remove = False
+ if CACHE_DIRECTORY:
+ path = CACHE_DIRECTORY
+ else:
+ path = tempfile.mkdtemp()
+ remove = True
+
+ return ModuleLoader(path)
+
+
+class BaseTemplate(object):
+ """Template base class.
+
+ Takes a string input which must be one of the following:
+
+ - a unicode string (or string on Python 3);
+ - a utf-8 encoded byte string;
+ - a byte string for an XML document that defines an encoding
+ in the document premamble;
+ - an HTML document that specifies the encoding via the META tag.
+
+ Note that the template input is decoded, parsed and compiled on
+ initialization.
+ """
+
+ default_encoding = "utf-8"
+
+ # This attribute is strictly informational in this template class
+ # and is used in exception formatting. It may be set on
+ # initialization using the optional ``filename`` keyword argument.
+ filename = '<string>'
+
+ _cooked = False
+
+ if DEBUG_MODE or CACHE_DIRECTORY:
+ loader = _make_module_loader()
+ else:
+ loader = MemoryLoader()
+
+ if DEBUG_MODE:
+ output_stream_factory = DebuggingOutputStream
+ else:
+ output_stream_factory = list
+
+ debug = DEBUG_MODE
+
+ # The ``builtins`` dictionary can be used by a template class to
+ # add symbols which may not be redefined and which are (cheaply)
+ # available in the template variable scope
+ builtins = {}
+
+ # The ``builtins`` dictionary is updated with this dictionary at
+ # cook time. Note that it can be provided at class initialization
+ # using the ``extra_builtins`` keyword argument.
+ extra_builtins = {}
+
+ # Expression engine must be provided by subclass
+ engine = None
+
+ # When ``strict`` is set, expressions must be valid at compile
+ # time. When not set, this is only required at evaluation time.
+ strict = True
+
+ def __init__(self, body=None, **config):
+ self.__dict__.update(config)
+
+ if body is not None:
+ self.write(body)
+
+ # This is only necessary if the ``debug`` flag was passed as a
+ # keyword argument
+ if self.__dict__.get('debug') is True:
+ self.loader = _make_module_loader()
+
+ def __call__(self, **kwargs):
+ return self.render(**kwargs)
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__, self.filename)
+
+ @property
+ def keep_body(self):
+ # By default, we only save the template body if we're
+ # in debugging mode (to save memory).
+ return self.__dict__.get('keep_body', DEBUG_MODE)
+
+ @property
+ def keep_source(self):
+ # By default, we only save the generated source code if we're
+ # in debugging mode (to save memory).
+ return self.__dict__.get('keep_source', DEBUG_MODE)
+
+ def cook(self, body):
+ digest = self._digest(body)
+ builtins_dict = self.builtins.copy()
+ builtins_dict.update(self.extra_builtins)
+ names, builtins = zip(*builtins_dict.items())
+ program = self._cook(body, digest, names)
+
+ initialize = program['initialize']
+ functions = initialize(*builtins)
+
+ for name, function in functions.items():
+ setattr(self, "_" + name, function)
+
+ self._cooked = True
+
+ if self.keep_body:
+ self.body = body
+
+ def cook_check(self):
+ assert self._cooked
+
+ def parse(self, body):
+ raise NotImplementedError("Must be implemented by subclass.")
+
+ def render(self, **__kw):
+ econtext = Scope(__kw)
+ rcontext = {}
+ self.cook_check()
+ stream = self.output_stream_factory()
+ try:
+ self._render(stream, econtext, rcontext)
+ except:
+ cls, exc, tb = sys.exc_info()
+ errors = rcontext.get('__error__')
+ if errors:
+ formatter = exc.__str__
+ if isinstance(formatter, ExceptionFormatter):
+ if errors is not formatter._errors:
+ formatter._errors.extend(errors)
+ raise
+
+ formatter = ExceptionFormatter(errors, econtext, rcontext)
+
+ try:
+ exc = create_formatted_exception(exc, cls, formatter)
+ except TypeError:
+ pass
+
+ raise_with_traceback(exc, tb)
+
+ raise
+
+ return join(stream)
+
+ def write(self, body):
+ if isinstance(body, byte_string):
+ body, encoding, content_type = read_bytes(
+ body, self.default_encoding
+ )
+ else:
+ content_type = body.startswith('<?xml')
+ encoding = None
+
+ self.content_type = content_type
+ self.content_encoding = encoding
+
+ self.cook(body)
+
+ def _get_module_name(self, digest):
+ return "%s.py" % digest
+
+ def _cook(self, body, digest, builtins):
+ name = self._get_module_name(digest)
+ cooked = self.loader.get(name)
+ if cooked is None:
+ try:
+ source = self._make(body, builtins)
+ if self.debug:
+ source = "# template: %s\n#\n%s" % (self.filename, source)
+ if self.keep_source:
+ self.source = source
+ cooked = self.loader.build(source, name)
+ except TemplateError:
+ exc = sys.exc_info()[1]
+ exc.filename = self.filename
+ raise
+ elif self.keep_source:
+ module = sys.modules.get(cooked.get('__name__'))
+ if module is not None:
+ self.source = inspect.getsource(module)
+ else:
+ self.source = None
+
+ return cooked
+
+ def _digest(self, body):
+ class_name = type(self).__name__.encode('utf-8')
+ sha = pkg_digest.copy()
+ sha.update(body.encode('utf-8', 'ignore'))
+ sha.update(class_name)
+ return sha.hexdigest()
+
+ def _compile(self, program, builtins):
+ compiler = Compiler(self.engine, program, builtins, strict=self.strict)
+ return compiler.code
+
+ def _make(self, body, builtins):
+ program = self.parse(body)
+ module = Module("initialize", program)
+ return self._compile(module, builtins)
+
+
+class BaseTemplateFile(BaseTemplate):
+ """File-based template base class.
+
+ Relative path names are supported only when a template loader is
+ provided as the ``loader`` parameter.
+ """
+
+ # Auto reload is not enabled by default because it's a significant
+ # performance hit
+ auto_reload = AUTO_RELOAD
+
+ def __init__(self, filename, auto_reload=None, **config):
+ # Normalize filename
+ filename = os.path.abspath(
+ os.path.normpath(os.path.expanduser(filename))
+ )
+
+ self.filename = filename
+
+ # Override reload setting only if value is provided explicitly
+ if auto_reload is not None:
+ self.auto_reload = auto_reload
+
+ super(BaseTemplateFile, self).__init__(**config)
+
+ if EAGER_PARSING:
+ self.cook_check()
+
+ def cook_check(self):
+ if self.auto_reload:
+ mtime = self.mtime()
+
+ if mtime != self._v_last_read:
+ self._v_last_read = mtime
+ self._cooked = False
+
+ if self._cooked is False:
+ body = self.read()
+ log.debug("cooking %r (%d bytes)..." % (self.filename, len(body)))
+ self.cook(body)
+
+ def mtime(self):
+ try:
+ return os.path.getmtime(self.filename)
+ except (IOError, OSError):
+ return 0
+
+ def read(self):
+ with open(self.filename, "rb") as f:
+ data = f.read()
+
+ body, encoding, content_type = read_bytes(
+ data, self.default_encoding
+ )
+
+ # In non-XML mode, we support various platform-specific line
+ # endings and convert them to the UNIX newline character
+ if content_type != "text/xml" and '\r' in body:
+ body = body.replace('\r\n', '\n').replace('\r', '\n')
+
+ self.content_type = content_type
+ self.content_encoding = encoding
+
+ return body
+
+ def _get_module_name(self, digest):
+ filename = os.path.basename(self.filename)
+ mangled = mangle(filename)
+ return "%s_%s.py" % (mangled, digest)
+
+ def _get_filename(self):
+ return self.__dict__.get('filename')
+
+ def _set_filename(self, filename):
+ self.__dict__['filename'] = filename
+ self._v_last_read = None
+ self._cooked = False
+
+ filename = property(_get_filename, _set_filename)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py b/lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py
@@ -0,0 +1,1 @@
+#
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt
@@ -0,0 +1,1 @@
+${'<Hello world>'}<&>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html
@@ -0,0 +1,7 @@
+<html>
+ <body py:with="text 'Hello world!'">
+ ${text}
+ $text
+ </body>
+ ${text | 'Goodbye world!'}
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt
@@ -0,0 +1,11 @@
+<html>
+ <body tal:define="text 'Hello world!'">
+ ${text}
+ </body>
+ <tal:check condition="exists: text">
+ bad
+ </tal:check>
+ <tal:check condition="not: exists: text">
+ ok
+ </tal:check>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <div tal:repeat="text ('Hello', 'Goodbye')">
+ <span tal:repeat="char ('!', '.')">${text}${char}</span>
+ </div>
+ <tal:check condition="not: exists: text">ok</tal:check>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc ></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt
@@ -0,0 +1,17 @@
+<html>
+ <body>
+ <div tal:content="'Hello world!'" />
+ <div tal:content="'Hello world!'" />1
+ 2<div tal:content="'Hello world!'" />
+ <div tal:content="'Hello world!'" />3
+ <div tal:content="'Hello world!'">4</div>5
+ 6<div tal:content="'Hello world!'"></div>
+ <div tal:content="1" />
+ <div tal:content="1.0" />
+ <div tal:content="True" />
+ <div tal:content="False" />
+ <div tal:content="0" />
+ <div tal:content="None" />
+ <div tal:replace="content" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc >
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt
@@ -0,0 +1,18 @@
+<html>
+ <body>
+ <span tal:attributes="class 'hello'" />
+ <span class="goodbye" tal:attributes="class 'hello'" />
+ <span CLASS="goodbye" tal:attributes="class 'hello'" />
+ <span tal:attributes="class None" />
+ <span a="1" b="2" c="3" tal:attributes="a None" />
+ <span a="1" b="2" c="3" tal:attributes="b None" />
+ <span a="1" b="2" c="3" tal:attributes="c None" />
+ <span a="1" b="2" c="3" tal:attributes="b None; c None" />
+ <span a="1" b="2" c="3" tal:attributes="b string:;;" />
+ <span a="1" b="2" c="3" tal:attributes="b string:&" />
+ <span class="hello" tal:attributes="class 'goodbye'" />
+ <span class="hello" tal:attributes="class '"goodbye"'" />
+ <span class="hello" tal:attributes="class '\'goodbye\''" />
+ <span class='hello' tal:attributes="class '\'goodbye\''" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <img class="default" tal:attributes="class default" />
+ <img tal:attributes="class default" />
+ <span tal:content="default">Default</span>
+ <span tal:content="True">Default</span>
+ <span tal:content="False">Default</span>
+ <span tal:content="default">
+ <em>${'Computed default'}</em>
+ </span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1 = "v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt
@@ -0,0 +1,9 @@
+<html>
+ <body class="ltr" tal:define="hash string:#">
+ <img src="${'#'}" alt="copyright (c) ${2010}" />
+ <img src="" alt="copyright (c) ${2010}" tal:attributes="src string:$hash" />
+ <img src="" alt="copyright (c) ${2010}" tal:attributes="src string:${hash}" />
+ <img src="${None}" alt="$ignored" />
+ <img src="" alt="${'%stype \'str\'%s' % (chr(60), chr(62))}" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1='v1'></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt
@@ -0,0 +1,15 @@
+<html>
+ <body>
+ ${'Hello world!'}
+ ${literal}
+ ${structure: literal.s}
+ ${"%stype 'str'%s" % (chr(60), chr(62))}
+ &&
+ ${None}
+ ${None or
+ 'Hello world'}
+ $leftalone
+ <div>${None}</div>
+ <div>${1 < 2 and 'Hello world' or None}</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc> </doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ ${nothing}
+ <div tal:attributes="class string:dynamic" class="static">
+ ${attrs['class']}
+ </div>
+ <div tal:define="nothing string:nothing">
+ ${nothing}
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&<>"'</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ ${literal}
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc> </doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div tal:content="text string:1 < 2" />
+ <div tal:content="structure string:2 < 3, 2&3, 2<3, 2>3" />
+ <div tal:content="structure string:3 ${'<'} 4" />
+ <div tal:content="structure '%d < %d' % (4, 5)" />
+ <div tal:replace="structure content" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1="v1" ></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div tal:content="text message" />
+ <div tal:content="structure message" />
+ <div tal:content="text string:${message}" />
+ <div tal:content="structure string:${message}" />
+ ${message}
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED a2 CDATA #IMPLIED>
+]>
+<doc a1="v1" a2="v2"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt
@@ -0,0 +1,21 @@
+<html>
+ <body>
+ <div i18n:translate="">
+ Hello world!
+ </div>
+ <div i18n:translate="hello_world">
+ Hello world!
+ </div>
+ <div i18n:translate="">
+ <sup>Hello world!</sup>
+ </div>
+ <div i18n:translate="">
+ Hello <em i18n:name="first">${'world'}</em>!
+ Goodbye <em i18n:name="second">${'planet'}</em>!
+ </div>
+ <div i18n:translate="hello_goodbye">
+ Hello <em i18n:name="first">${'world'}</em>!
+ Goodbye <em i18n:name="second">${'planet'}</em>!
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc : CDATA #IMPLIED>
+]>
+<doc :="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <table>
+ <tr tal:repeat="i (1,2)">
+ <td tal:repeat="j (1,2)">
+ [${i},${j}]
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc _.-0123456789 CDATA #IMPLIED>
+]>
+<doc _.-0123456789="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt
@@ -0,0 +1,7 @@
+<html>
+ <body>
+ <span tal:repeat="i (3,4)">
+ <span tal:repeat="j (3,4)">[${i},${j}]</span>
+ </span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc abcdefghijklmnopqrstuvwxyz CDATA #IMPLIED>
+]>
+<doc abcdefghijklmnopqrstuvwxyz="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt
@@ -0,0 +1,10 @@
+<html>
+ <body>
+ <div i18n:translate="">
+ Price:
+ <span i18n:name="price" i18n:translate="">
+ Per kilo <em i18n:name="amount">${12.5}</em>
+ </span>
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc ABCDEFGHIJKLMNOPQRSTUVWXYZ CDATA #IMPLIED>
+]>
+<doc ABCDEFGHIJKLMNOPQRSTUVWXYZ="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <div i18n:translate="" tal:content="string:Hello world!">
+ Hello world!
+ </div>
+ <img alt="${'Hello world!'}" i18n:attributes="alt" />
+ <img alt="${'Hello world!'}" i18n:attributes="alt hello_world" />
+ <img tal:attributes="alt 'Hello world!'" i18n:attributes="alt" />
+ <img tal:attributes="alt 'Hello world!'" i18n:attributes="alt hello_world" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><?pi?></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <div tal:omit-tag="">Hello world!</div>
+ <div tal:omit-tag="">1
+ Hello world!
+ 2</div>3
+ 4<div tal:omit-tag="True">Hello world!</div>
+ <div tal:omit-tag="False">Hello world!</div>
+ <div class="omitted" tal:omit-tag="True">Hello world!</div>
+ <div class="${'omitted'}" tal:omit-tag="True">Hello world!</div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><?pi some data ? > <??></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt
@@ -0,0 +1,13 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <div i18n:translate="" tal:omit-tag="">
+ <span i18n:name="monthname"
+ i18n:translate=""
+ tal:content="'october'"
+ tal:omit-tag="">monthname</span>
+ <span i18n:name="year"
+ i18n:translate=""
+ tal:content="1982"
+ tal:omit-tag="">year</span>
+ </div>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[<foo>]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt
@@ -0,0 +1,13 @@
+<html>
+ <body>
+ <div tal:replace="'Hello world!'" />
+ <div tal:replace="'Hello world!'" />1
+ 2<div tal:replace="'Hello world!'" />
+ <div tal:replace="'Hello world!'" />3
+ <div tal:replace="'Hello world!'">4</div>5
+ 6<div tal:replace="'Hello world!'"></div>
+ <div tal:replace="1" />
+ <div tal:replace="1.0" />
+ <div tal:replace="True" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[<&]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt
@@ -0,0 +1,10 @@
+<html>
+ <body>
+ <div id="test" tal:attributes="class python: 'abc' + 2" tal:on-error="nothing" />
+ <div tal:on-error="string:${type(error.value).__name__} thrown at ${error.lineno}:${error.offset}.">
+ <div tal:content="undefined" />
+ </div>
+ <div tal:replace="undefined" tal:on-error="nothing" />
+ <div tal:content="undefined" tal:on-error="nothing" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[<&]>]]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt
@@ -0,0 +1,16 @@
+<html>
+ <body i18n:domain="old">
+ <div i18n:domain="new" i18n:translate="">
+ Hello world!
+ </div>
+ <div i18n:translate="">
+ Hello world!
+ </div>
+ <div class="test" i18n:domain="new" i18n:attributes="class">
+ Hello world!
+ </div>
+ <div class="test" i18n:domain="new" i18n:attributes="class test_msgid">
+ Hello world!
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><!-- a comment --></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt
@@ -0,0 +1,13 @@
+<html>
+ <body>
+ <div tal:switch="True">
+ <span tal:case="False">bad</span>
+ <span tal:case="True">ok</span>
+ <span tal:case="not not True">ok</span>
+ </div>
+ <div tal:switch="True">
+ <span tal:case="False">bad</span>
+ <span tal:case="default">ok</span>
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><!-- a comment ->--></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt
@@ -0,0 +1,6 @@
+<html>
+ <body tal:condition="True">
+ <span tal:define="selector False" tal:condition="selector">bad</span>
+ <span tal:condition="True">ok</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt
@@ -0,0 +1,16 @@
+<html>
+ <body>
+ <tal:first>
+ <tal:second>
+ ${'first'}
+ </tal:second>
+ second
+ </tal:first>
+ <tal:block condition="True">
+ ok
+ </tal:block>
+ <tal:block condition="False">
+ bad
+ </tal:block>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo)>
+<!ELEMENT foo (#PCDATA)>
+<!ENTITY e "<foo></foo>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt
@@ -0,0 +1,14 @@
+<html>
+ <body>
+ <ul>
+ <tal:item repeat="i (1, 2, 3)"><li tal:content="i" /></tal:item>
+ <span tal:omit-tag="" tal:repeat="j (1, 2, 3)"><li tal:content="j" /></span>
+ <tal:count>
+ <tal:count-loop repeat="count (1, 2, 3)">
+ <span tal:replace="count"
+ /><tal:comma condition="not repeat['count'].end">,</tal:comma>
+ </tal:count-loop>
+ </tal:count>.
+ </ul>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo*)>
+<!ELEMENT foo (#PCDATA)>
+]>
+<doc><foo/><foo></foo></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt
@@ -0,0 +1,13 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <ul>
+ <li tal:attributes="class repeat['i'].even()+repeat['i'].odd()" name="${i}-${repeat.i.index}" tal:repeat="i range(3)"><span tal:replace="i" /></li>
+ </ul>
+ <ul>
+ <li tal:attributes="class repeat['i'].even+repeat['i'].odd"
+ tal:repeat="i range(3)"><span tal:replace="i" /></li>
+ </ul>
+ <ul>
+ <li tal:repeat="i range(3)"><span tal:condition="repeat['i'].even" tal:replace="repeat['i'].even" /><span tal:condition="repeat['i'].odd" tal:replace="repeat['i'].odd" /></li>
+ </ul>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo*)>
+<!ELEMENT foo EMPTY>
+]>
+<doc><foo/><foo></foo></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt
@@ -0,0 +1,11 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <span id="test"
+ class="dummy"
+ onClick=""
+ tal:define="a 'abc'"
+ tal:attributes="class 'def' + a + default; style 'hij'; onClick 'alert();;'"
+ tal:content="a + 'ghi'" />
+ <span tal:replace="'Hello World!'">Hello <b>Universe</b>!</span>
+ <span tal:replace="'Hello World!'"><b>Hello Universe!</b></span>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo*)>
+<!ELEMENT foo ANY>
+]>
+<doc><foo/><foo></foo></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt
@@ -0,0 +1,6 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <option tal:attributes="selected True"></option>
+ <option tal:attributes="selected False"></option>
+ <option tal:attributes="selected None"></option>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt
@@ -0,0 +1,5 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <a rel="self" href="http://repoze.org" id="link-id"
+ tal:attributes="href 'http://python.org'" />
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0'?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt
@@ -0,0 +1,7 @@
+<html>
+ <body>
+ <div tal:repeat="(i, j) ((1, 2), (3, 4))">
+ ${repeat['i', 'j'].number}, ${i}, ${j}
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml
@@ -0,0 +1,5 @@
+<?xml version = "1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt
@@ -0,0 +1,7 @@
+<div>
+ <tal:example replace="'Hello World!'" />
+ <tal:example tal:replace="'Hello World!'" />
+ <tal:div content="'Hello World!'" />
+ <tal:multiple repeat="i range(3)" replace="i" />
+ <tal:div condition="True">True</tal:div>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt
@@ -0,0 +1,20 @@
+<html i18n:domain="master" metal:define-macro="main" tal:define="content nothing">
+ <head>
+ <title metal:define-slot="title"
+ metal:define-macro="title"
+ tal:define="has_title exists: title"
+ tal:content="title if has_title else default">Master template</title>
+ </head>
+ <body>
+ <div id="content">
+ <metal:content define-slot="content">
+ <!-- content here -->
+ </metal:content>
+ </div>
+ <div id="footer">
+ <metal:footer define-slot="body-footer" tal:content="nothing">
+ <!-- footer here -->
+ </metal:footer>
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' standalone='yes'?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt
@@ -0,0 +1,1 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding="UTF-8" standalone='yes'?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt
@@ -0,0 +1,1 @@
+<html metal:use-macro="load('032-master-template.pt')" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc/>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+ <title metal:fill-slot="title" tal:define="kind 'New'">
+ ${kind} title
+ </title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt
@@ -0,0 +1,2 @@
+<html tal:define="title string:New title"
+ metal:use-macro="load('032-master-template.pt').macros['main']" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
+<?pi data?>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']" >
+ <metal:content metal:fill-slot="content">
+ <span tal:condition="content is None">ok</span>
+ </metal:content>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
+<!-- comment -->
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt
@@ -0,0 +1,6 @@
+<metal:globals use-macro="load('039-globals.pt')" />
+<html>
+ <body>
+ <span tal:condition="content is None">ok</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml
@@ -0,0 +1,6 @@
+<!-- comment -->
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt
@@ -0,0 +1,1 @@
+<tal:globals define="global content None" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml
@@ -0,0 +1,5 @@
+<?pi data?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ metal:define-macro="master"
+ template-macros="${' '.join(template.macros.names)}"
+ macros="${' '.join(macros.names)}">
+ <metal:block tal:define="foo 'foo'">
+ ${foo}
+ <div metal:define-slot="content" tal:replace="None">
+ <!-- will be replaced -->
+ </div>
+ <span template-macros="${' '.join(template.macros.names)}"
+ macros="${' '.join(macros.names)}">
+ <!-- demonstrate difference between
+ `template` and `macros` symbol -->
+ </span>
+ </metal:block>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1=""<&>'"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt
@@ -0,0 +1,22 @@
+<html>
+ <body>
+ <div i18n:translate="">
+ Hello
+ <tal:nested condition="True">
+ <span i18n:name="world">world!</span>
+ </tal:nested>
+ </div>
+ <div i18n:translate="hello">
+ Hello
+ <tal:nested condition="True">
+ <span i18n:name="world">world!</span>
+ </tal:nested>
+ </div>
+ <div i18n:translate="">
+ Goodbye
+ <tal:nested condition="False">
+ <span i18n:name="world">world!</span>
+ </tal:nested>
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1="A"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+ <metal:footer fill-slot="body-footer">New footer</metal:footer>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>A</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt
@@ -0,0 +1,19 @@
+<html>
+ <body>
+ <tal:macros condition="0">
+
+ <metal:outer define-macro="outer">
+ <metal:inner use-macro="template.macros['inner']" />
+ </metal:outer>
+
+ <metal:inner define-macro="inner">
+ ${title}
+ </metal:inner>
+
+ </tal:macros>
+
+ <div tal:define="title string:My title"
+ metal:use-macro="template.macros['outer']"
+ />
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 CDATA #IMPLIED>
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc a1="foo
+bar"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt
@@ -0,0 +1,5 @@
+<html>
+ <body tal:define="(a, b) 'a', 'b'">
+ ${a}, ${b}
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (e*)>
+<!ELEMENT e EMPTY>
+<!ATTLIST e a1 CDATA "v1" a2 CDATA "v2" a3 CDATA #IMPLIED>
+]>
+<doc>
+<e a3="v3"/>
+<e a1="w1"/>
+<e a2="w2" a3="v3"/>
+</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE application [
+ <!ENTITY nbsp "\ ">
+]>
+<application xmlns="http://research.sun.com/wadl/2006/10"
+ xsi:schemaLocation="http://research.sun.com/wadl/2006/10/wadl.xsd"
+ xmlns:wadl="http://research.sun.com/wadl/2006/10"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <resources tal:define="path '/'">
+ <resource path="${path}">ZZZ YYY XXX</resource>
+ </resources>
+</application>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA "v1">
+<!ATTLIST doc a1 CDATA "z1">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt
@@ -0,0 +1,6 @@
+<html metal:define-macro="extended"
+ metal:extend-macro="load('032-master-template.pt').macros['main']">
+ <metal:footer fill-slot="body-footer">
+ <span metal:define-slot="kind">New</span> footer
+ </metal:footer>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA "v1">
+<!ATTLIST doc a2 CDATA "v2">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('046-extend-macro.pt').macros['extended']">
+ <em metal:fill-slot="kind">Extended</em>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>X
+Y</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('046-extend-macro.pt').macros['extended']">
+ <metal:footer fill-slot="body-footer">
+ Extended footer
+ </metal:footer>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>]</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <pre tal:content="string:amp=& lt=<" />
+ <pre tal:content="structure string:amp=& lt=<" />
+ <script tal:replace="structure string:<script />" />
+ <script tal:replace="string:<script />" />
+ <script tal:replace="string:${'<'}script /${'>'}" />
+ <script tal:replace="structure string:${'<'}script /${'>'}" />
+ <img alt="1 < 2: ${1 < 2}" />
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c3cc797b5954881cc794f6720674a8bfa13aacbe
GIT binary patch
[stripped]
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt
@@ -0,0 +1,6 @@
+<html metal:define-macro="main"
+ metal:use-macro="load('032-master-template.pt').macros['main']">
+ <metal:content fill-slot="content">
+ Default content
+ </metal:content>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050.xml
new file mode 100644
index 0000000000000000000000000000000000000000..12303b1af2185eb29894629b99431fea831367b1
GIT binary patch
[stripped]
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('050-define-macro-and-use-not-extend.pt').macros['main']">
+ <metal:content fill-slot="content">
+ <span>Filled content</span>
+ </metal:content>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7ae8f6c73a4b47ec18492ebefed16c63f5f5ef22
GIT binary patch
[stripped]
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt
@@ -0,0 +1,8 @@
+<html metal:define-macro="main"
+ metal:use-macro="load('032-master-template.pt').macros['main']">
+ <metal:content fill-slot="content">
+ <span i18n:domain="mydomain" i18n:translate="">
+ Translated content
+ </span>
+ </metal:content>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>ðô¿½</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <a tal:attributes="href string:@@view">test</a>
+ <a href="${'@@'}view">test</a>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ENTITY e "<e/>">
+<!ELEMENT doc (e)>
+<!ELEMENT e EMPTY>
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt
@@ -0,0 +1,3 @@
+<div tal:define="datetime import: datetime.datetime">
+ ${datetime(1984, 12, 31).isoformat()}
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+
+
+<doc
+></doc
+>
+
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt
@@ -0,0 +1,4 @@
+<div tal:define="obj {'foo': 'bar', 'boo': {'bar': 'baz'}}">
+ ${obj.foo}
+ ${obj.boo.bar}
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<?pi data?>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt
@@ -0,0 +1,7 @@
+<html>
+ <body>
+ <tal:first comment="ignored">
+ Namespace tag
+ </tal:first>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>A</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <div tal:condition="False" tal:repeat="item bad_input" />
+ <div tal:define="sequence 1, 2, 3"
+ tal:repeat="item sequence"
+ tal:replace="item" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a*)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <script tal:define="field {'oid': 1}; values 'values'; options 'options'">
+ deform.addCallback(
+ '${field.oid}',
+ function (oid) {
+ $('#' + oid).autocomplete({source: ${values}});
+ $('#' + oid).autocomplete("option", ${options});
+ }
+ );
+ </script>
+ </head>
+ <body>
+ <!-- Form -->
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS #IMPLIED>
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc a1=" 1 2 "></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <span onclick="alert(true && false);">test</span>
+ <span onclick="alert(${str(True).lower()} && ${str(False).lower()});">test</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (e*)>
+<!ELEMENT e EMPTY>
+<!ATTLIST e a1 CDATA #IMPLIED a2 CDATA #IMPLIED a3 CDATA #IMPLIED>
+]>
+<doc>
+<e a1="v1" a2="v2" a3="v3"/>
+<e a1="w1" a2="v2"/>
+<e a1="v1" a2="w2" a3="v3"/>
+</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt
@@ -0,0 +1,8 @@
+<html metal:define-macro="main">
+ <head>
+ <title><metal:title define-slot="title">Untitled</metal:title></title>
+ </head>
+ <body>
+ <h1><metal:title define-slot="title">Untitled</metal:title></h1>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>X
Y</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('060-macro-with-multiple-same-slots.pt').macros['main']">
+ <metal:title fill-slot="title">My document</metal:title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>£</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt
@@ -0,0 +1,27 @@
+<div>
+ <!--! ${dropped} -->
+</div>
+
+<div>
+ <!--? ${left alone} -->
+</div>
+
+<div>
+ <!-- ${'not left alone'} -->
+</div>
+
+<div meta:interpolation="true">
+ <!-- ${'not left alone'} -->
+</div>
+
+<div meta:interpolation="false">
+ <!-- ${left alone} -->
+</div>
+
+<!--[if IE ${6}]>
+ Special instructions for IE 6 here
+<![endif]-->
+
+<!--?[if IE 6]>
+ ${left alone}
+<![endif]-->
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>เจมสà¹</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt
@@ -0,0 +1,4 @@
+<div tal:define="foo 1 + \
+ 1">
+ ${foo}
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE à¹à¸à¸¡à¸ªà¹ [
+<!ELEMENT à¹à¸à¸¡à¸ªà¹ (#PCDATA)>
+]>
+<à¹à¸à¸¡à¸ªà¹></à¹à¸à¸¡à¸ªà¹>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt
@@ -0,0 +1,4 @@
+<tal:block>
+ <div id="test" class="${'test'}">
+ </div>
+</tal:block>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>𐀀􏿽</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt
@@ -0,0 +1,6 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+ <title tal:define="title string:Title"
+ metal:fill-slot="title"
+ metal:use-macro="load('032-master-template.pt').macros['title']" />
+ <div metal:fill-slot="content">Content</div>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY e "<">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt
@@ -0,0 +1,1 @@
+<html tal:define="hello_world load: hello_world.pt" metal:use-macro="hello_world" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+<!-- 34 is double quote -->
+<!ENTITY e1 """>
+]>
+<doc a1="&e1;"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <img src="#" tal:attributes="class 1 > 0 and 'up' or 0 < 1 and 'down';" />
+ <img src="#" tal:attributes="class 0 > 1 and 'up' or 0 < 1 and 'down';" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>
</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <span tal:content="string:0 < 1 or 0 > 1" />
+ <span tal:content="structure string:0 < 1 or 0 > 1" />
+ <span class="0 < 1 or 0 > 1" />
+ <span>0 < 1 or 0 > 1</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "
">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+ <title metal:fill-slot="title" i18n:domain="test" i18n:translate="title">Title</title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!NOTATION n PUBLIC "whatever">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt
@@ -0,0 +1,3 @@
+<html i18n:domain="test" metal:use-macro="load('032-master-template.pt').macros['main']">
+ <title metal:fill-slot="title" i18n:translate="title">Title</title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY % e "<!ELEMENT doc (#PCDATA)>">
+%e;
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <input type="input" tal:attributes="checked True" />
+ <input type="input" tal:attributes="checked False" />
+ <input type="input" tal:attributes="checked None" />
+ <input type="input" checked="checked" tal:attributes="checked default" />
+ <input type="input" checked tal:attributes="checked default" />
+ <input type="input" tal:attributes="checked default" />
+ <input type="input" class="field" tal:attributes="class True" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ID #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt
@@ -0,0 +1,13 @@
+<html>
+ <body>
+ <ul>
+ <li tal:repeat="i range(1, 4)" class="${'odd' if i % 2 != 0 else default}">${i}</li>
+ </ul>
+ <ul>
+ <li tal:repeat="i range(1, 4)" class="${'odd' if i % 2 != 0 else None}">${i}</li>
+ </ul>
+ <ul>
+ <li tal:repeat="i range(1, 4)" class="${'odd' if i % 2 != 0 else False}">${i}</li>
+ </ul>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a IDREF #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>${'my title'} â ${'my site'}</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a IDREFS #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="windows-1251" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>${'my title'} ${'my site'}</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ENTITY #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt
@@ -0,0 +1,11 @@
+<metal:page define-macro="master">
+ <tal:block metal:use-macro="load('032-master-template.pt').macros['main']">
+
+ <metal:block fill-slot="content">
+ <metal:override define-slot="content">
+ foo
+ </metal:override>
+ </metal:block>
+
+ </tal:block>
+</metal:page>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ENTITIES #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt
@@ -0,0 +1,3 @@
+<metal:page use-macro="load('075-nested-macros.pt').macros['master']">
+ <metal:block fill-slot="content">bar</metal:block>
+</metal:page>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a NOTATION (n1|n2) #IMPLIED>
+<!NOTATION n1 SYSTEM "http://www.w3.org/">
+<!NOTATION n2 SYSTEM "http://www.w3.org/">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt
@@ -0,0 +1,1 @@
+<input type="hidden" id="uploadify_label_file_title" i18n:domain="test" i18n:attributes="value Title" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a (1|2) #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt
@@ -0,0 +1,23 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ tal:omit-tag=""
+ tal:define="id 'foo'">
+ <body>
+ <span id="toDataContainer"
+ tal:attributes="id string:${id}-toDataContainer">
+ <script type="text/javascript" tal:content="string:
+ copyDataForSubmit('${id}');">
+ // initial copying of field "field.to" --> "field"
+ copyDataForSubmit("<i tal:replace="${id}"/>");
+ </script>
+ </span>
+ <tal:block
+ repeat="value python: (1, 2, 3)"
+ ><span class="selected-option"
+ tal:content="value"
+ /><tal:block condition="not:repeat.value.end">, </tal:block
+ ></tal:block
+>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #REQUIRED>
+]>
+<doc a="v"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt
@@ -0,0 +1,16 @@
+<html tal:define="request dict(site_url='http://host')">
+ <head>
+ <title>Welcome</title>
+ </head>
+ <body>
+ <h1>Welcome</h1>
+ <span>An edge case: ${.</span>
+ <img tal:define="site_url request.site_url" alt="Site logo" href="${site_url}/logo.png" />
+ <img alt="Site logo" href="${request.site_url}/logo.png" />
+ <div id="content">
+ foo.
+ <br />
+ bar.
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #FIXED "v">
+]>
+<doc a="v"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt
@@ -0,0 +1,6 @@
+<tal:component xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ Hello world
+</tal:component>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #FIXED "v">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt
@@ -0,0 +1,1 @@
+<html metal:use-macro="load: chameleon:tests/inputs/hello_world.pt" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a, b, c)>
+<!ELEMENT a (a?)>
+<!ELEMENT b (b*)>
+<!ELEMENT c (a | b)+>
+]>
+<doc><a/><b/><c><a/></c></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt
@@ -0,0 +1,1 @@
+<html tal:define="name 'hello_world'" metal:use-macro="load: chameleon:tests/inputs/${name}.pt" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY % e SYSTEM "e.dtd">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt
@@ -0,0 +1,2 @@
+<html tal:define="template load: 032-master-template.pt"
+ metal:use-macro="template['main']" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY % e PUBLIC 'whatever' "e.dtd">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <script>
+ <![CDATA[
+ alert("${'Hello world!'}");
+ ]]>
+ </script>
+ </head>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml
@@ -0,0 +1,1 @@
+<!DOCTYPE doc [<!ELEMENT doc (#PCDATA)>]><doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt
@@ -0,0 +1,11 @@
+<html tal:define="request dict(site_url='http://host')" i18n:domain="new">
+ <head>
+ <title>Welcome</title>
+ </head>
+ <body>
+ <h1>Welcome</h1>
+ <p i18n:translate="">
+ <a i18n:name="click_here" i18n:translate="" href="${request.site_url}">Click here</a> to continue.
+ </p>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY % e "<foo>">
+<!ENTITY e "">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt
@@ -0,0 +1,10 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+ <body>
+ <div metal:fill-slot="content">
+ <div tal:condition="True">
+ <a href="#">Chart</a>
+ <div id="chart-info"/>
+ </div>
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "">
+<!ENTITY e "<foo>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt
@@ -0,0 +1,28 @@
+<?python
+ foo = [1, 2, 3] ?>
+
+<ul>
+ <li tal:repeat="f foo" tal:content="f" />
+</ul>
+
+<?python
+ foo = [1, 2, 3]
+ boo = [4, 5, 6]
+?>
+
+<ul>
+ <li tal:repeat="(f, g) zip(foo, boo)" tal:content="f + g" />
+</ul>
+
+<div>
+ <?python numbers = map(str, range(1, 10)) ?>
+ Please input a number from the range ${", ".join(numbers)}.
+</div>
+
+<div>
+ <?python
+ def function(i):
+ return i + 1
+ ?>
+ 41 + 1 = ${function(41)}.
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ENTITY e "<foo/>">
+<!ELEMENT doc (foo)>
+<!ELEMENT foo EMPTY>
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt
@@ -0,0 +1,2 @@
+<span tal:replace="python: ', '.join((
+ 'a', 'b', 'c'))" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "<foo>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY e "𐀀􏿽">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ATTLIST e a NOTATION (n) #IMPLIED>
+<!ELEMENT doc (e)*>
+<!ELEMENT e (#PCDATA)>
+<!NOTATION n PUBLIC "whatever">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!NOTATION n SYSTEM "http://www.w3.org/">
+<!ENTITY e SYSTEM "http://www.w3.org/" NDATA n>
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ENTITY "e">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a)*>
+<!ELEMENT a EMPTY>
+]>
+<doc>
+<a/>
+ <a/> <a/>
+
+
+</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>
+
</doc>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ENTITY % e "foo">
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA "%e;">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 CDATA #IMPLIED>
+<!ATTLIST doc a1 NMTOKENS #IMPLIED>
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc a1="1 2"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS " 1 2 ">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY % e SYSTEM "097.ent">
+<!ATTLIST doc a1 CDATA "v1">
+%e;
+<!ATTLIST doc a2 CDATA "v2">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><?pi x
+y?></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY e PUBLIC ";!*#@$_%" "100.xml">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <h1><br><br>Hello world</h1>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e """>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <h1 class=title align=center>Hello world</h1>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="""></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <select name="foo2" multiple style="visibility: hidden">
+ <option value="1">this should</option>
+ <option value="2">remain hidden right?</option>
+ </select>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x
y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x
y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "
+">
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x&e;y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a=""></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "
">
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x&e;y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a NMTOKENS #IMPLIED>
+]>
+<doc a=" x y "></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a | b)>
+<!ELEMENT a (#PCDATA)>
+]>
+<doc><a></a></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST e a CDATA #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "<![CDATA[&foo;]]>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e1 "&e2;">
+<!ENTITY e2 "v">
+]>
+<doc>&e1;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[
+]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY rsqb "]">
+]>
+<doc>]</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY rsqb "]]">
+]>
+<doc>]</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc ANY>
+]>
+<doc><!-- -á --></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt
@@ -0,0 +1,1 @@
+<div>Hello, ${name | 'undefined'}.</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ ${'Hello world!'}
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt
@@ -0,0 +1,1 @@
+${'Hello world!'}
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html
@@ -0,0 +1,7 @@
+<html>
+ <body>
+ Hello world!
+ Hello world!
+ </body>
+ Goodbye world!
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ Hello world!
+ </body>
+
+
+ ok
+
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt
@@ -0,0 +1,1 @@
+<Hello world><&>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt
@@ -0,0 +1,13 @@
+<html>
+ <body>
+ <div>
+ <span>Hello!</span>
+ <span>Hello.</span>
+ </div>
+ <div>
+ <span>Goodbye!</span>
+ <span>Goodbye.</span>
+ </div>
+ ok
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt
@@ -0,0 +1,17 @@
+<html>
+ <body>
+ <div>Hello world!</div>
+ <div>Hello world!</div>1
+ 2<div>Hello world!</div>
+ <div>Hello world!</div>3
+ <div>Hello world!</div>5
+ 6<div>Hello world!</div>
+ <div>1</div>
+ <div>1.0</div>
+ <div>True</div>
+ <div>False</div>
+ <div>0</div>
+ <div></div>
+ <div>Hello world!</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt
@@ -0,0 +1,18 @@
+<html>
+ <body>
+ <span class="hello" />
+ <span class="hello" />
+ <span class="hello" />
+ <span />
+ <span b="2" c="3" />
+ <span a="1" c="3" />
+ <span a="1" b="2" />
+ <span a="1" />
+ <span a="1" b=";" c="3" />
+ <span a="1" b="&" c="3" />
+ <span class="goodbye" />
+ <span class=""goodbye"" />
+ <span class="'goodbye'" />
+ <span class=''goodbye'' />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <img class="default" />
+ <img />
+ <span>Default</span>
+ <span>True</span>
+ <span>False</span>
+ <span>
+ <em>Computed default</em>
+ </span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt
@@ -0,0 +1,9 @@
+<html>
+ <body class="ltr">
+ <img src="#" alt="copyright (c) 2010" />
+ <img src="#" alt="copyright (c) 2010" />
+ <img src="#" alt="copyright (c) 2010" />
+ <img alt="$ignored" />
+ <img src="" alt="<type 'str'>" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt
@@ -0,0 +1,14 @@
+<html>
+ <body>
+ Hello world!
+ <div>Hello world!</div>
+ <div>Hello world!</div>
+ <type 'str'>
+ &&
+
+ Hello world
+ $leftalone
+ <div></div>
+ <div>Hello world</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+
+ <div class="dynamic">
+ static
+ </div>
+ <div>
+ nothing
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <div>Hello world!</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>1 < 2</div>
+ <div>2 < 3, 2&3, 2<3, 2>3</div>
+ <div>3 < 4</div>
+ <div>4 < 5</div>
+ <div>Hello world!</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>Message ('message' translation into 'en')</div>
+ <div>Message ('message' translation into 'en')</div>
+ <div>Message ('message' translation into 'en')</div>
+ <div>Message ('message' translation into 'en')</div>
+ Message ('message' translation into 'en')
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>Message</div>
+ <div>Message</div>
+ <div>Message</div>
+ <div>Message</div>
+ Message
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>Hello world! ('Hello world!' translation into 'en')</div>
+ <div>Hello world! ('hello_world' translation into 'en')</div>
+ <div><sup>Hello world!</sup> ('<sup>Hello world!</sup>' translation into 'en')</div>
+ <div>Hello <em>world</em>! Goodbye <em>planet</em>! ('Hello ${first}! Goodbye ${second}!' translation into 'en')</div>
+ <div>Hello <em>world</em>! Goodbye <em>planet</em>! ('hello_goodbye' translation into 'en')</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>Hello world!</div>
+ <div>Hello world!</div>
+ <div><sup>Hello world!</sup></div>
+ <div>Hello <em>world</em>! Goodbye <em>planet</em>!</div>
+ <div>Hello <em>world</em>! Goodbye <em>planet</em>!</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt
@@ -0,0 +1,22 @@
+<html>
+ <body>
+ <table>
+ <tr>
+ <td>
+ [1,1]
+ </td>
+ <td>
+ [1,2]
+ </td>
+ </tr>
+ <tr>
+ <td>
+ [2,1]
+ </td>
+ <td>
+ [2,2]
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <span>
+ <span>[3,3]</span>
+ <span>[3,4]</span>
+ </span>
+ <span>
+ <span>[4,3]</span>
+ <span>[4,4]</span>
+ </span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <div>Price: <span>Per kilo <em>12.5</em> ('Per kilo ${amount}' translation into 'en')</span> ('Price: ${price}' translation into 'en')</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <div>Price: <span>Per kilo <em>12.5</em></span></div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>Hello world! ('Hello world!' translation into 'en')</div>
+ <img alt="Hello world! ('Hello world!' translation into 'en')" />
+ <img alt="Hello world! ('hello_world' translation into 'en')" />
+ <img alt="Hello world! ('Hello world!' translation into 'en')" />
+ <img alt="Hello world! ('hello_world' translation into 'en')" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt
@@ -0,0 +1,9 @@
+<html>
+ <body>
+ <div>Hello world!</div>
+ <img alt="Hello world!" />
+ <img alt="Hello world!" />
+ <img alt="Hello world!" />
+ <img alt="Hello world!" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ Hello world!
+ 1
+ Hello world!
+ 23
+ 4Hello world!
+ <div>Hello world!</div>
+ Hello world!
+ Hello world!
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ october ('october' translation into 'en') 1982 ('1982' translation into 'en') ('${monthname} ${year}' translation into 'en')
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ october 1982
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt
@@ -0,0 +1,13 @@
+<html>
+ <body>
+ Hello world!
+ Hello world!1
+ 2Hello world!
+ Hello world!3
+ Hello world!5
+ 6Hello world!
+ 1
+ 1.0
+ True
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <div id="test"></div>
+ <div>NameError thrown at 5:24.</div>
+ <div></div>
+ <div></div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <div>Hello world! ('Hello world!' translation into 'en' with domain 'new')</div>
+ <div>Hello world! ('Hello world!' translation into 'en' with domain 'old')</div>
+ <div class="test ('test' translation into 'en' with domain 'new')">
+ Hello world!
+ </div>
+ <div class="test ('test_msgid' translation into 'en' with domain 'new')">
+ Hello world!
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <div>Hello world!</div>
+ <div>Hello world!</div>
+ <div class="test">
+ Hello world!
+ </div>
+ <div class="test">
+ Hello world!
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt
@@ -0,0 +1,13 @@
+<html>
+ <body>
+ <div>
+
+ <span>ok</span>
+ <span>ok</span>
+ </div>
+ <div>
+
+ <span>ok</span>
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+
+ <span>ok</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt
@@ -0,0 +1,14 @@
+<html>
+ <body>
+
+
+ first
+
+ second
+
+
+ ok
+
+
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt
@@ -0,0 +1,23 @@
+<html>
+ <body>
+ <ul>
+ <li>1</li>
+ <li>2</li>
+ <li>3</li>
+ <li>1</li>
+ <li>2</li>
+ <li>3</li>
+
+
+ 1,
+
+
+ 2,
+
+
+ 3
+
+ .
+ </ul>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt
@@ -0,0 +1,17 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ <ul>
+ <li name="0-0" class="even">0</li>
+ <li name="1-1" class="odd">1</li>
+ <li name="2-2" class="even">2</li>
+ </ul>
+ <ul>
+ <li class="even">0</li>
+ <li class="odd">1</li>
+ <li class="even">2</li>
+ </ul>
+ <ul>
+ <li>even</li>
+ <li>odd</li>
+ <li>even</li>
+ </ul>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt
@@ -0,0 +1,7 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ <span id="test"
+ class="defabcdummy"
+ onClick="alert();" style="hij">abcghi</span>
+ Hello World!
+ Hello World!
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt
@@ -0,0 +1,5 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ <option selected="True"></option>
+ <option></option>
+ <option></option>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ <a rel="self" href="http://python.org" id="link-id" />
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt
@@ -0,0 +1,10 @@
+<html>
+ <body>
+ <div>
+ 1, 1, 2
+ </div>
+ <div>
+ 2, 3, 4
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt
@@ -0,0 +1,9 @@
+<div>
+ Hello World!
+ Hello World!
+ Hello World!
+ 0
+ 1
+ 2
+ True
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>
+ New title
+ </title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>New title</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <span>ok</span>
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt
@@ -0,0 +1,6 @@
+
+<html>
+ <body>
+ <span>ok</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/039.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/039.pt
new file mode 100644
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ template-macros="master"
+ macros="master">
+
+ foo
+
+ <span template-macros="master"
+ macros="master">
+ <!-- demonstrate difference between
+ `template` and `macros` symbol -->
+ </span>
+
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt
@@ -0,0 +1,7 @@
+<html>
+ <body>
+ <div>Hello <span>world!</span></div>
+ <div>Hello <span>world!</span></div>
+ <div>Goodbye</div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+ New footer
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+
+
+
+
+ My title
+
+
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ a, b
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE application [
+ <!ENTITY nbsp "\ ">
+]>
+<application xmlns="http://research.sun.com/wadl/2006/10"
+ xsi:schemaLocation="http://research.sun.com/wadl/2006/10/wadl.xsd"
+ xmlns:wadl="http://research.sun.com/wadl/2006/10"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <resources>
+ <resource path="/">ZZZ YYY XXX</resource>
+ </resources>
+</application>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ <span>New</span> footer
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ <em>Extended</em> footer
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ Extended footer
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <pre>amp=& lt=<</pre>
+ <pre>amp=& lt=<</pre>
+ <script />
+ <script />
+ <script />
+ <script />
+ <img alt="1 < 2: True" />
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ Default content
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ Default content
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <span>Translated content</span>
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <a href="@@view">test</a>
+ <a href="@@view">test</a>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt
@@ -0,0 +1,3 @@
+<div>
+ 1984-12-31T00:00:00
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt
@@ -0,0 +1,4 @@
+<div>
+ bar
+ baz
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt
@@ -0,0 +1,7 @@
+<html>
+ <body>
+
+ Namespace tag
+
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt
@@ -0,0 +1,8 @@
+<html>
+ <body>
+
+ 1
+ 2
+ 3
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <script>
+ deform.addCallback(
+ '1',
+ function (oid) {
+ $('#' + oid).autocomplete({source: values});
+ $('#' + oid).autocomplete("option", options);
+ }
+ );
+ </script>
+ </head>
+ <body>
+ <!-- Form -->
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <span onclick="alert(true && false);">test</span>
+ <span onclick="alert(true && false);">test</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Untitled</title>
+ </head>
+ <body>
+ <h1>Untitled</h1>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>My document</title>
+ </head>
+ <body>
+ <h1>My document</h1>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt
@@ -0,0 +1,27 @@
+<div>
+
+</div>
+
+<div>
+ <!-- ${left alone} -->
+</div>
+
+<div>
+ <!-- not left alone -->
+</div>
+
+<div>
+ <!-- not left alone -->
+</div>
+
+<div>
+ <!-- ${left alone} -->
+</div>
+
+<!--[if IE 6]>
+ Special instructions for IE 6 here
+<![endif]-->
+
+<!--[if IE 6]>
+ ${left alone}
+<![endif]-->
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt
@@ -0,0 +1,3 @@
+<div>
+ 2
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt
@@ -0,0 +1,3 @@
+
+ <div id="test" class="test">
+ </div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt
@@ -0,0 +1,13 @@
+<html>
+ <head>
+ <title>Title</title>
+ </head>
+ <body>
+ <div id="content">
+ <div>Content</div>
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ Hello world!
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <img src="#" class="up" />
+ <img src="#" class="down" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <span>0 < 1 or 0 > 1</span>
+ <span>0 < 1 or 0 > 1</span>
+ <span class="0 < 1 or 0 > 1" />
+ <span>0 < 1 or 0 > 1</span>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Title ('title' translation into 'en' with domain 'test')</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Title</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Title ('title' translation into 'en' with domain 'test')</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Title</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <input type="input" checked="True" />
+ <input type="input" />
+ <input type="input" />
+ <input type="input" checked="checked" />
+ <input type="input" checked />
+ <input type="input" />
+ <input type="input" class="True" />
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt
@@ -0,0 +1,19 @@
+<html>
+ <body>
+ <ul>
+ <li class="odd">1</li>
+ <li>2</li>
+ <li class="odd">3</li>
+ </ul>
+ <ul>
+ <li class="odd">1</li>
+ <li>2</li>
+ <li class="odd">3</li>
+ </ul>
+ <ul>
+ <li class="odd">1</li>
+ <li>2</li>
+ <li class="odd">3</li>
+ </ul>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>my title â my site</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="windows-1251" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>my title my site</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt
@@ -0,0 +1,19 @@
+
+ <html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+
+ foo
+
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt
@@ -0,0 +1,17 @@
+
+ <html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+<BLANKLINE>
+ bar
+<BLANKLINE>
+ </div>
+ <div id="footer">
+<BLANKLINE>
+ </div>
+ </body>
+</html>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt
@@ -0,0 +1,1 @@
+<input type="hidden" id="uploadify_label_file_title" value="value ('Title' translation into 'en' with domain 'test')" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt
@@ -0,0 +1,1 @@
+<input type="hidden" id="uploadify_label_file_title" value="value" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt
@@ -0,0 +1,11 @@
+
+ <body>
+ <span id="foo-toDataContainer">
+ <script type="text/javascript">
+ copyDataForSubmit('foo');</script>
+ </span>
+ <span class="selected-option">1</span>,
+ <span class="selected-option">2</span>,
+ <span class="selected-option">3</span>
+ </body>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <title>Welcome ('Welcome' translation into 'en')</title>
+ </head>
+ <body>
+ <h1>Welcome ('Welcome' translation into 'en')</h1>
+ <span>An edge case: ${. ('An edge case: ${.' translation into 'en')</span>
+ <img alt="Site logo ('Site logo' translation into 'en')" href="http://host/logo.png" />
+ <img alt="Site logo ('Site logo' translation into 'en')" href="http://host/logo.png" />
+ <div id="content">
+ foo. ('foo.' translation into 'en')
+ <br />
+ bar. ('bar.' translation into 'en')
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <title>Welcome</title>
+ </head>
+ <body>
+ <h1>Welcome</h1>
+ <span>An edge case: ${.</span>
+ <img alt="Site logo" href="http://host/logo.png" />
+ <img alt="Site logo" href="http://host/logo.png" />
+ <div id="content">
+ foo.
+ <br />
+ bar.
+ </div>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt
@@ -0,0 +1,3 @@
+
+ Hello world
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ Hello world!
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ Hello world!
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+
+ <!-- content here -->
+
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <script>
+ <![CDATA[
+ alert("Hello world!");
+ ]]>
+ </script>
+ </head>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <title>Welcome</title>
+ </head>
+ <body>
+ <h1>Welcome</h1>
+ <p><a href="http://host">Click here ('Click here' translation into 'en' with domain 'new')</a> to continue. ('${click_here} to continue.' translation into 'en' with domain 'new')</p>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <title>Welcome</title>
+ </head>
+ <body>
+ <h1>Welcome</h1>
+ <p><a href="http://host">Click here</a> to continue.</p>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <title>Master template</title>
+ </head>
+ <body>
+ <div id="content">
+ <div>
+ <div>
+ <a href="#">Chart</a>
+ <div id="chart-info"/>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt
@@ -0,0 +1,25 @@
+
+
+<ul>
+ <li>1</li>
+ <li>2</li>
+ <li>3</li>
+</ul>
+
+
+
+<ul>
+ <li>5</li>
+ <li>7</li>
+ <li>9</li>
+</ul>
+
+<div>
+
+ Please input a number from the range 1, 2, 3, 4, 5, 6, 7, 8, 9.
+</div>
+
+<div>
+
+ 41 + 1 = 42.
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt
@@ -0,0 +1,1 @@
+a, b, c
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <h1><br><br>Hello world</h1>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <h1 class=title align=center>Hello world</h1>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html
@@ -0,0 +1,8 @@
+<html>
+ <body>
+ <select name="foo2" multiple style="visibility: hidden">
+ <option value="1">this should</option>
+ <option value="2">remain hidden right?</option>
+ </select>
+ </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt
@@ -0,0 +1,1 @@
+<div>Hello, undefined.</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ Hello world!
+ </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt
@@ -0,0 +1,1 @@
+Hello world!
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py
@@ -0,0 +1,40 @@
+import unittest
+import doctest
+
+OPTIONFLAGS = (doctest.ELLIPSIS |
+ doctest.REPORT_ONLY_FIRST_FAILURE)
+
+
+class DoctestCase(unittest.TestCase):
+ def __new__(self, test):
+ return getattr(self, test)()
+
+ @classmethod
+ def test_tal(cls):
+ from chameleon import tal
+ return doctest.DocTestSuite(
+ tal, optionflags=OPTIONFLAGS)
+
+ @classmethod
+ def test_tales(cls):
+ from chameleon import tales
+ return doctest.DocTestSuite(
+ tales, optionflags=OPTIONFLAGS)
+
+ @classmethod
+ def test_utils(cls):
+ from chameleon import utils
+ return doctest.DocTestSuite(
+ utils, optionflags=OPTIONFLAGS)
+
+ @classmethod
+ def test_exc(cls):
+ from chameleon import exc
+ return doctest.DocTestSuite(
+ exc, optionflags=OPTIONFLAGS)
+
+ @classmethod
+ def test_compiler(cls):
+ from chameleon import compiler
+ return doctest.DocTestSuite(
+ compiler, optionflags=OPTIONFLAGS)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py
@@ -0,0 +1,79 @@
+import unittest
+
+
+class LoadTests:
+ def _makeOne(self, search_path=None, **kwargs):
+ klass = self._getTargetClass()
+ return klass(search_path, **kwargs)
+
+ def _getTargetClass(self):
+ from chameleon.loader import TemplateLoader
+ return TemplateLoader
+
+ def test_load_relative(self):
+ import os
+ here = os.path.join(os.path.dirname(__file__), "inputs")
+ loader = self._makeOne(search_path=[here])
+ result = self._load(loader, 'hello_world.pt')
+ self.assertEqual(result.filename, os.path.join(here, 'hello_world.pt'))
+
+ def test_consecutive_loads(self):
+ import os
+ here = os.path.join(os.path.dirname(__file__), "inputs")
+ loader = self._makeOne(search_path=[here])
+
+ self.assertTrue(
+ self._load(loader, 'hello_world.pt') is \
+ self._load(loader, 'hello_world.pt'))
+
+ def test_load_relative_badpath_in_searchpath(self):
+ import os
+ here = os.path.join(os.path.dirname(__file__), "inputs")
+ loader = self._makeOne(search_path=[os.path.join(here, 'none'), here])
+ result = self._load(loader, 'hello_world.pt')
+ self.assertEqual(result.filename, os.path.join(here, 'hello_world.pt'))
+
+ def test_load_abs(self):
+ import os
+ here = os.path.join(os.path.dirname(__file__), "inputs")
+ loader = self._makeOne()
+ abs = os.path.join(here, 'hello_world.pt')
+ result = self._load(loader, abs)
+ self.assertEqual(result.filename, abs)
+
+
+class LoadPageTests(unittest.TestCase, LoadTests):
+ def _load(self, loader, filename):
+ from chameleon.zpt import template
+ return loader.load(filename, template.PageTemplateFile)
+
+
+class ZPTLoadTests(unittest.TestCase):
+ def _makeOne(self, *args, **kwargs):
+ import os
+ here = os.path.join(os.path.dirname(__file__), "inputs")
+ from chameleon.zpt import loader
+ return loader.TemplateLoader(here, **kwargs)
+
+ def test_load_xml(self):
+ loader = self._makeOne()
+ template = loader.load("hello_world.pt", "xml")
+ from chameleon.zpt.template import PageTemplateFile
+ self.assertTrue(isinstance(template, PageTemplateFile))
+
+ def test_load_text(self):
+ loader = self._makeOne()
+ template = loader.load("hello_world.txt", "text")
+ from chameleon.zpt.template import PageTextTemplateFile
+ self.assertTrue(isinstance(template, PageTextTemplateFile))
+
+ def test_load_getitem_gets_xml_file(self):
+ loader = self._makeOne()
+ template = loader["hello_world.pt"]
+ from chameleon.zpt.template import PageTemplateFile
+ self.assertTrue(isinstance(template, PageTemplateFile))
+
+
+def test_suite():
+ import sys
+ return unittest.findTestCases(sys.modules[__name__])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py
@@ -0,0 +1,92 @@
+from __future__ import with_statement
+
+import sys
+
+from unittest import TestCase
+
+from ..namespaces import XML_NS
+from ..namespaces import XMLNS_NS
+from ..namespaces import PY_NS
+
+
+class ParserTest(TestCase):
+ def test_sample_files(self):
+ import os
+ import traceback
+ path = os.path.join(os.path.dirname(__file__), "inputs")
+ for filename in os.listdir(path):
+ if not filename.endswith('.html'):
+ continue
+
+ with open(os.path.join(path, filename), 'rb') as f:
+ source = f.read()
+
+ from ..utils import read_encoded
+ try:
+ want = read_encoded(source)
+ except UnicodeDecodeError:
+ exc = sys.exc_info()[1]
+ self.fail("%s - %s" % (exc, filename))
+
+ from ..tokenize import iter_xml
+ from ..parser import ElementParser
+ try:
+ tokens = iter_xml(want)
+ parser = ElementParser(tokens, {
+ 'xmlns': XMLNS_NS,
+ 'xml': XML_NS,
+ 'py': PY_NS,
+ })
+ elements = tuple(parser)
+ except:
+ self.fail(traceback.format_exc())
+
+ output = []
+
+ def render(kind, args):
+ if kind == 'element':
+ # start tag
+ tag, end, children = args
+ output.append("%(prefix)s%(name)s" % tag)
+
+ for attr in tag['attrs']:
+ output.append(
+ "%(space)s%(name)s%(eq)s%(quote)s%(value)s%(quote)s" % \
+ attr
+ )
+
+ output.append("%(suffix)s" % tag)
+
+ # children
+ for item in children:
+ render(*item)
+
+ # end tag
+ output.append(
+ "%(prefix)s%(name)s%(space)s%(suffix)s" % end
+ )
+ elif kind == 'text':
+ text = args[0]
+ output.append(text)
+ elif kind == 'start_tag':
+ node = args[0]
+ output.append(
+ "%(prefix)s%(name)s%(space)s%(suffix)s" % node
+ )
+ else:
+ raise RuntimeError("Not implemented: %s." % kind)
+
+ for kind, args in elements:
+ render(kind, args)
+
+ got = "".join(output)
+
+ from doctest import OutputChecker
+ checker = OutputChecker()
+
+ if checker.check_output(want, got, 0) is False:
+ from doctest import Example
+ example = Example(f.name, want)
+ diff = checker.output_difference(
+ example, got, 0)
+ self.fail("(%s) - \n%s" % (f.name, diff))
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py
@@ -0,0 +1,124 @@
+from __future__ import with_statement
+
+import os
+import unittest
+import tempfile
+import shutil
+
+from chameleon.utils import unicode_string
+from chameleon.utils import encode_string
+
+
+class TypeSniffingTestCase(unittest.TestCase):
+ def setUp(self):
+ self.tempdir = tempfile.mkdtemp(prefix='chameleon-tests')
+
+ def tearDown(self):
+ shutil.rmtree(self.tempdir)
+
+ def _get_temporary_file(self):
+ filename = os.path.join(self.tempdir, 'template.py')
+ assert not os.path.exists(filename)
+ f = open(filename, 'w')
+ f.flush()
+ f.close()
+ return filename
+
+ def get_template(self, text):
+ fn = self._get_temporary_file()
+
+ with open(fn, 'wb') as tmpfile:
+ tmpfile.write(text)
+
+ from chameleon.template import BaseTemplateFile
+
+ class DummyTemplateFile(BaseTemplateFile):
+ def cook(self, body):
+ self.body = body
+
+ template = DummyTemplateFile(fn)
+ template.cook_check()
+ return template
+
+ def check_content_type(self, text, expected_type):
+ from chameleon.utils import read_bytes
+ content_type = read_bytes(text, 'ascii')[2]
+ self.assertEqual(content_type, expected_type)
+
+ def test_xml_encoding(self):
+ from chameleon.utils import xml_prefixes
+
+ document1 = unicode_string(
+ "<?xml version='1.0' encoding='ascii'?><doc/>"
+ )
+ document2 = unicode_string(
+ "<?xml\tversion='1.0' encoding='ascii'?><doc/>"
+ )
+
+ for bom, encoding in xml_prefixes:
+ try:
+ "".encode(encoding)
+ except LookupError:
+ # System does not support this encoding
+ continue
+
+ self.check_content_type(document1.encode(encoding), "text/xml")
+ self.check_content_type(document2.encode(encoding), "text/xml")
+
+ HTML_PUBLIC_ID = "-//W3C//DTD HTML 4.01 Transitional//EN"
+ HTML_SYSTEM_ID = "http://www.w3.org/TR/html4/loose.dtd"
+
+ # Couldn't find the code that handles this... yet.
+ # def test_sniffer_html_ascii(self):
+ # self.check_content_type(
+ # "<!DOCTYPE html [ SYSTEM '%s' ]><html></html>"
+ # % self.HTML_SYSTEM_ID,
+ # "text/html")
+ # self.check_content_type(
+ # "<html><head><title>sample document</title></head></html>",
+ # "text/html")
+
+ # TODO: This reflects a case that simply isn't handled by the
+ # sniffer; there are many, but it gets it right more often than
+ # before.
+ def donttest_sniffer_xml_simple(self):
+ self.check_content_type("<doc><element/></doc>", "text/xml")
+
+ def test_html_default_encoding(self):
+ body = encode_string(
+ '<html><head><title>' \
+ '\xc3\x90\xc2\xa2\xc3\x90\xc2\xb5' \
+ '\xc3\x91\xc2\x81\xc3\x91\xc2\x82' \
+ '</title></head></html>')
+
+ template = self.get_template(body)
+ self.assertEqual(template.body, body.decode('utf-8'))
+
+ def test_html_encoding_by_meta(self):
+ body = encode_string(
+ '<html><head><title>' \
+ '\xc3\x92\xc3\xa5\xc3\xb1\xc3\xb2' \
+ '</title><meta http-equiv="Content-Type"' \
+ ' content="text/html; charset=windows-1251"/>' \
+ "</head></html>")
+
+ template = self.get_template(body)
+ self.assertEqual(template.body, body.decode('windows-1251'))
+
+ def test_xhtml(self):
+ body = encode_string(
+ '<html><head><title>' \
+ '\xc3\x92\xc3\xa5\xc3\xb1\xc3\xb2' \
+ '</title><meta http-equiv="Content-Type"' \
+ ' content="text/html; charset=windows-1251"/>' \
+ "</head></html>")
+
+ template = self.get_template(body)
+ self.assertEqual(template.body, body.decode('windows-1251'))
+
+
+def test_suite():
+ return unittest.makeSuite(TypeSniffingTestCase)
+
+if __name__ == "__main__":
+ unittest.main(defaultTest="test_suite")
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py
@@ -0,0 +1,679 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import with_statement
+
+import re
+import os
+import sys
+import shutil
+import tempfile
+
+from functools import wraps
+from functools import partial
+
+try:
+ from unittest2 import TestCase
+except ImportError:
+ from unittest import TestCase
+
+
+from chameleon.utils import byte_string
+
+
+class Message(object):
+ def __str__(self):
+ return "message"
+
+
+class ImportTestCase(TestCase):
+ def test_pagetemplates(self):
+ from chameleon import PageTemplate
+ from chameleon import PageTemplateFile
+ from chameleon import PageTemplateLoader
+
+ def test_pagetexttemplates(self):
+ from chameleon import PageTextTemplate
+ from chameleon import PageTextTemplateFile
+
+
+class TemplateFileTestCase(TestCase):
+ @property
+ def _class(self):
+ from chameleon.template import BaseTemplateFile
+
+ class TestTemplateFile(BaseTemplateFile):
+ cook_count = 0
+
+ def cook(self, body):
+ self.cook_count += 1
+ self._cooked = True
+
+ return TestTemplateFile
+
+ def setUp(self):
+ self.tempdir = tempfile.mkdtemp(prefix='chameleon-tests')
+
+ def tearDown(self):
+ shutil.rmtree(self.tempdir)
+
+ def _get_temporary_file(self):
+ filename = os.path.join(self.tempdir, 'template.py')
+ assert not os.path.exists(filename)
+ f = open(filename, 'w')
+ f.flush()
+ f.close()
+ return filename
+
+ def test_cook_check(self):
+ fn = self._get_temporary_file()
+ template = self._class(fn)
+ template.cook_check()
+ self.assertEqual(template.cook_count, 1)
+
+ def test_auto_reload(self):
+ fn = self._get_temporary_file()
+
+ # set time in past
+ os.utime(fn, (0, 0))
+
+ template = self._class(fn, auto_reload=True)
+ template.cook_check()
+
+ # a second cook check makes no difference
+ template.cook_check()
+ self.assertEqual(template.cook_count, 1)
+
+ # set current time on file
+ os.utime(fn, None)
+
+ # file is reloaded
+ template.cook_check()
+ self.assertEqual(template.cook_count, 2)
+
+ def test_relative_is_expanded_to_cwd(self):
+ template = self._class("___does_not_exist___")
+ try:
+ template.cook_check()
+ except IOError:
+ exc = sys.exc_info()[1]
+ self.assertEqual(
+ os.getcwd(),
+ os.path.dirname(exc.filename)
+ )
+ else:
+ self.fail("Expected OSError.")
+
+
+class RenderTestCase(TestCase):
+ root = os.path.dirname(__file__)
+
+ def find_files(self, ext):
+ inputs = os.path.join(self.root, "inputs")
+ outputs = os.path.join(self.root, "outputs")
+ for filename in sorted(os.listdir(inputs)):
+ name, extension = os.path.splitext(filename)
+ if extension != ext:
+ continue
+ path = os.path.join(inputs, filename)
+
+ # if there's no output file, treat document as static and
+ # expect intput equal to output
+ import glob
+ globbed = tuple(glob.iglob(os.path.join(
+ outputs, "%s*%s" % (name.split('-', 1)[0], ext))))
+
+ if not globbed:
+ self.fail("Missing output for: %s." % name)
+
+ for output in globbed:
+ name, ext = os.path.splitext(output)
+ basename = os.path.basename(name)
+ if '-' in basename:
+ language = basename.split('-')[1]
+ else:
+ language = None
+
+ yield path, output, language
+
+
+class ZopePageTemplatesTest(RenderTestCase):
+ @property
+ def from_string(body):
+ from ..zpt.template import PageTemplate
+ return partial(PageTemplate, keep_source=True)
+
+ @property
+ def from_file(body):
+ from ..zpt.template import PageTemplateFile
+ return partial(PageTemplateFile, keep_source=True)
+
+ def template(body):
+ def decorator(func):
+ @wraps(func)
+ def wrapper(self):
+ template = self.from_string(body)
+ return func(self, template)
+
+ return wrapper
+ return decorator
+
+ def error(body):
+ def decorator(func):
+ @wraps(func)
+ def wrapper(self):
+ from chameleon.exc import TemplateError
+ try:
+ template = self.from_string(body)
+ except TemplateError:
+ exc = sys.exc_info()[1]
+ return func(self, body, exc)
+ else:
+ self.fail("Expected exception.")
+
+ return wrapper
+ return decorator
+
+ def test_syntax_error_in_strict_mode(self):
+ from chameleon.exc import ExpressionError
+
+ self.assertRaises(
+ ExpressionError,
+ self.from_string,
+ """<tal:block replace='bad /// ' />""",
+ strict=True
+ )
+
+ def test_syntax_error_in_non_strict_mode(self):
+ from chameleon.exc import ExpressionError
+
+ body = """<tal:block replace='bad /// ' />"""
+ template = self.from_string(body, strict=False)
+
+ try:
+ template()
+ except ExpressionError:
+ exc = sys.exc_info()[1]
+ self.assertTrue(body[exc.offset:].startswith('bad ///'))
+ else:
+ self.fail("Expected exception")
+
+ @error("""<tal:dummy attributes=\"dummy 'dummy'\" />""")
+ def test_attributes_on_tal_tag_fails(self, body, exc):
+ self.assertTrue(body[exc.offset:].startswith('dummy'))
+
+ @error("""<tal:dummy i18n:attributes=\"foo, bar\" />""")
+ def test_i18n_attributes_with_non_identifiers(self, body, exc):
+ self.assertTrue(body[exc.offset:].startswith('foo,'))
+
+ @error("""<tal:dummy repeat=\"key,value mydict.items()\">""")
+ def test_repeat_syntax_error_message(self, body, exc):
+ self.assertTrue(body[exc.offset:].startswith('key,value'))
+
+ def test_encoded(self):
+ filename = '074-encoded-template.pt'
+ with open(os.path.join(self.root, 'inputs', filename), 'rb') as f:
+ body = f.read()
+
+ self.from_string(body)
+
+ def test_utf8_encoded(self):
+ filename = '073-utf8-encoded.pt'
+ with open(os.path.join(self.root, 'inputs', filename), 'rb') as f:
+ body = f.read()
+
+ self.from_string(body)
+
+ def test_unicode_decode_error(self):
+ template = self.from_file(
+ os.path.join(self.root, 'inputs', 'greeting.pt')
+ )
+
+ string = native = "the artist formerly known as ƤÅÃÆÄÄ"
+ try:
+ string = string.decode('utf-8')
+ except AttributeError:
+ pass
+
+ class name:
+ @staticmethod
+ def __html__():
+ # This raises a decoding exception
+ string.encode('utf-8').decode('ascii')
+
+ self.fail("Expected exception raised.")
+
+ try:
+ template(name=name)
+ except UnicodeDecodeError:
+ exc = sys.exc_info()[1]
+ formatted = str(exc)
+
+ # There's a marker under the expression that has the
+ # unicode decode error
+ self.assertTrue('^^^^^' in formatted)
+ self.assertTrue(native in formatted)
+ else:
+ self.fail("expected error")
+
+ def test_custom_encoding_for_str_or_bytes_in_content(self):
+ string = '<div>ТеÑÑ${text}</div>'
+ try:
+ string = string.decode('utf-8')
+ except AttributeError:
+ pass
+
+ template = self.from_string(string, encoding="windows-1251")
+
+ text = 'ТеÑÑ'
+
+ try:
+ text = text.decode('utf-8')
+ except AttributeError:
+ pass
+
+ rendered = template(text=text.encode('windows-1251'))
+
+ self.assertEqual(
+ rendered,
+ string.replace('${text}', text)
+ )
+
+ def test_custom_encoding_for_str_or_bytes_in_attributes(self):
+ string = '<img tal="ТеÑÑ${text}" />'
+ try:
+ string = string.decode('utf-8')
+ except AttributeError:
+ pass
+
+ template = self.from_string(string, encoding="windows-1251")
+
+ text = 'ТеÑÑ'
+
+ try:
+ text = text.decode('utf-8')
+ except AttributeError:
+ pass
+
+ rendered = template(text=text.encode('windows-1251'))
+
+ self.assertEqual(
+ rendered,
+ string.replace('${text}', text)
+ )
+
+ def test_null_translate_function(self):
+ template = self.from_string('${test}', translate=None)
+ rendered = template(test=object())
+ self.assertTrue('object' in rendered)
+
+ def test_object_substitution_coerce_to_str(self):
+ template = self.from_string('${test}', translate=None)
+
+ class dummy(object):
+ def __repr__(inst):
+ self.fail("call not expected")
+
+ def __str__(inst):
+ return '<dummy>'
+
+ rendered = template(test=dummy())
+ self.assertEqual(rendered, '<dummy>')
+
+ def test_repr(self):
+ template = self.from_file(
+ os.path.join(self.root, 'inputs', 'hello_world.pt')
+ )
+ self.assertTrue(template.filename in repr(template))
+
+ def test_underscore_variable(self):
+ template = self.from_string(
+ "<div tal:define=\"_dummy 'foo'\">${_dummy}</div>"
+ )
+ self.assertTrue(template(), "<div>foo</div>")
+
+ def test_trim_attribute_space(self):
+ document = '''<div
+ class="document"
+ id="test"
+ tal:attributes="class string:${default} test"
+ />'''
+
+ result1 = self.from_string(
+ document)()
+
+ result2 = self.from_string(
+ document, trim_attribute_space=True)()
+
+ self.assertEqual(result1.count(" "), 49)
+ self.assertEqual(result2.count(" "), 4)
+ self.assertTrue(" />" in result1)
+ self.assertTrue(" />" in result2)
+
+ def test_exception(self):
+ from traceback import format_exception_only
+
+ template = self.from_string(
+ "<div tal:define=\"dummy foo\">${dummy}</div>"
+ )
+ try:
+ template()
+ except:
+ exc = sys.exc_info()[1]
+ formatted = str(exc)
+ self.assertFalse('NameError:' in formatted)
+ self.assertTrue('foo' in formatted)
+ self.assertTrue('(1:23)' in formatted)
+
+ formatted_exc = "\n".join(format_exception_only(type(exc), exc))
+ self.assertTrue('NameError: foo' in formatted_exc)
+ else:
+ self.fail("expected error")
+
+ def test_create_formatted_exception(self):
+ from chameleon.utils import create_formatted_exception
+
+ exc = create_formatted_exception(NameError('foo'), NameError, str)
+ self.assertEqual(exc.args, ('foo', ))
+
+ class MyNameError(NameError):
+ def __init__(self, boo):
+ NameError.__init__(self, boo)
+ self.bar = boo
+
+ exc = create_formatted_exception(MyNameError('foo'), MyNameError, str)
+ self.assertEqual(exc.args, ('foo', ))
+ self.assertEqual(exc.bar, 'foo')
+
+ def test_create_formatted_exception_no_subclass(self):
+ from chameleon.utils import create_formatted_exception
+
+ class DifficultMetaClass(type):
+ def __init__(self, class_name, bases, namespace):
+ if not bases == (BaseException, ):
+ raise TypeError(bases)
+
+ Difficult = DifficultMetaClass('Difficult', (BaseException, ), {'args': ()})
+
+ exc = create_formatted_exception(Difficult(), Difficult, str)
+ self.assertEqual(exc.args, ())
+
+ def test_error_handler_makes_safe_copy(self):
+ calls = []
+
+ class TestException(Exception):
+ def __init__(self, *args, **kwargs):
+ calls.append((args, kwargs))
+
+ def _render(stream, econtext, rcontext):
+ exc = TestException('foo', bar='baz')
+ rcontext['__error__'] = ('expression', 1, 42, 'test.pt', exc),
+ raise exc
+
+ template = self.from_string("")
+ template._render = _render
+ try:
+ template()
+ except TestException:
+ self.assertEqual(calls, [(('foo', ), {'bar': 'baz'})])
+ exc = sys.exc_info()[1]
+ formatted = str(exc)
+ self.assertTrue('TestException' in formatted)
+ self.assertTrue('"expression"' in formatted)
+ self.assertTrue('(1:42)' in formatted)
+ else:
+ self.fail("unexpected error")
+
+ def test_double_underscore_variable(self):
+ from chameleon.exc import TranslationError
+ self.assertRaises(
+ TranslationError, self.from_string,
+ "<div tal:define=\"__dummy 'foo'\">${__dummy}</div>",
+ )
+
+ def test_compiler_internals_are_disallowed(self):
+ from chameleon.compiler import COMPILER_INTERNALS_OR_DISALLOWED
+ from chameleon.exc import TranslationError
+
+ for name in COMPILER_INTERNALS_OR_DISALLOWED:
+ body = "<d tal:define=\"%s 'foo'\">${%s}</d>" % (name, name)
+ self.assertRaises(TranslationError, self.from_string, body)
+
+ def test_fast_translate_mapping(self):
+ template = self.from_string(
+ '<div i18n:translate="">'
+ '<span i18n:name="name">foo</span>'
+ '</div>')
+
+ self.assertEqual(template(), '<div><span>foo</span></div>')
+
+ def test_translate_is_not_an_internal(self):
+ macro = self.from_string('<span i18n:translate="">bar</span>')
+ template = self.from_string(
+ '''
+ <tal:defs define="translate string:">
+ <span i18n:translate="">foo</span>
+ <metal:macro use-macro="macro" />
+ </tal:defs>
+ ''')
+
+ result = template(macro=macro)
+ self.assertTrue('foo' in result)
+ self.assertTrue('foo' in result)
+
+ def test_literal_false(self):
+ template = self.from_string(
+ '<input type="input" tal:attributes="checked False" />'
+ '<input type="input" tal:attributes="checked True" />'
+ '<input type="input" tal:attributes="checked None" />'
+ '<input type="input" tal:attributes="checked default" />',
+ literal_false=True,
+ )
+
+ self.assertEqual(
+ template(),
+ '<input type="input" checked="False" />'
+ '<input type="input" checked="True" />'
+ '<input type="input" />'
+ '<input type="input" />',
+ template.source
+ )
+
+ def test_boolean_attributes(self):
+ template = self.from_string(
+ '<input type="input" tal:attributes="checked False" />'
+ '<input type="input" tal:attributes="checked True" />'
+ '<input type="input" tal:attributes="checked None" />'
+ '<input type="input" tal:attributes="checked \'\'" />'
+ '<input type="input" tal:attributes="checked default" />'
+ '<input type="input" checked="checked" tal:attributes="checked default" />',
+ boolean_attributes=set(['checked'])
+ )
+
+ self.assertEqual(
+ template(),
+ '<input type="input" />'
+ '<input type="input" checked="checked" />'
+ '<input type="input" />'
+ '<input type="input" />'
+ '<input type="input" />'
+ '<input type="input" checked="checked" />',
+ template.source
+ )
+
+ def test_default_debug_flag(self):
+ from chameleon.config import DEBUG_MODE
+ template = self.from_file(
+ os.path.join(self.root, 'inputs', 'hello_world.pt'),
+ )
+ self.assertEqual(template.debug, DEBUG_MODE)
+ self.assertTrue('debug' not in template.__dict__)
+
+ def test_debug_flag_on_string(self):
+ from chameleon.loader import ModuleLoader
+
+ with open(os.path.join(self.root, 'inputs', 'hello_world.pt')) as f:
+ source = f.read()
+
+ template = self.from_string(source, debug=True)
+
+ self.assertTrue(template.debug)
+ self.assertTrue(isinstance(template.loader, ModuleLoader))
+
+ def test_debug_flag_on_file(self):
+ from chameleon.loader import ModuleLoader
+ template = self.from_file(
+ os.path.join(self.root, 'inputs', 'hello_world.pt'),
+ debug=True,
+ )
+ self.assertTrue(template.debug)
+ self.assertTrue(isinstance(template.loader, ModuleLoader))
+
+ def test_tag_mismatch(self):
+ from chameleon.exc import ParseError
+
+ try:
+ self.from_string("""
+ <div metal:use-macro="layout">
+ <div metal:fill-slot="name"></dav>
+ </div>
+ """)
+ except ParseError:
+ exc = sys.exc_info()[1]
+ self.assertTrue("</dav>" in str(exc))
+ else:
+ self.fail("Expected error.")
+
+
+class ZopeTemplatesTestSuite(RenderTestCase):
+ def setUp(self):
+ self.temp_path = temp_path = tempfile.mkdtemp()
+
+ @self.addCleanup
+ def cleanup(path=temp_path):
+ shutil.rmtree(path)
+
+ def test_pt_files(self):
+ from ..zpt.template import PageTemplateFile
+
+ class Literal(object):
+ def __init__(self, s):
+ self.s = s
+
+ def __html__(self):
+ return self.s
+
+ def __str__(self):
+ raise RuntimeError(
+ "%r is a literal." % self.s)
+
+ from chameleon.loader import TemplateLoader
+ loader = TemplateLoader(os.path.join(self.root, "inputs"))
+
+ self.execute(
+ ".pt", PageTemplateFile,
+ literal=Literal("<div>Hello world!</div>"),
+ content="<div>Hello world!</div>",
+ message=Message(),
+ load=loader.bind(PageTemplateFile),
+ )
+
+ def test_txt_files(self):
+ from ..zpt.template import PageTextTemplateFile
+ self.execute(".txt", PageTextTemplateFile)
+
+ def execute(self, ext, factory, **kwargs):
+ def translate(msgid, domain=None, mapping=None, context=None,
+ target_language=None, default=None):
+ if default is None:
+ default = str(msgid)
+
+ if isinstance(msgid, Message):
+ default = "Message"
+
+ if mapping:
+ default = re.sub(r'\${([a-z_]+)}', r'%(\1)s', default) % \
+ mapping
+
+ if target_language is None:
+ return default
+
+ if domain is None:
+ with_domain = ""
+ else:
+ with_domain = " with domain '%s'" % domain
+
+ stripped = default.rstrip('\n ')
+ return "%s ('%s' translation into '%s'%s)%s" % (
+ stripped, msgid, target_language, with_domain,
+ default[len(stripped):]
+ )
+
+ for input_path, output_path, language in self.find_files(ext):
+ # Make friendly title so we can locate the generated
+ # source when debugging
+ self.shortDescription = lambda: input_path
+
+ # Very implicitly enable implicit translation based on
+ # a string included in the input path:
+ implicit_i18n = 'implicit-i18n' in input_path
+ implicit_i18n_attrs = ("alt", "title") if implicit_i18n else ()
+
+ template = factory(
+ input_path,
+ keep_source=True,
+ strict=False,
+ implicit_i18n_translate=implicit_i18n,
+ implicit_i18n_attributes=implicit_i18n_attrs,
+ )
+
+ params = kwargs.copy()
+ params.update({
+ 'translate': translate,
+ 'target_language': language,
+ })
+
+ template.cook_check()
+
+ try:
+ got = template.render(**params)
+ except:
+ import traceback
+ e = traceback.format_exc()
+ self.fail("%s\n\n Example source:\n\n%s" % (e, "\n".join(
+ ["%#03.d%s" % (lineno + 1, line and " " + line or "")
+ for (lineno, line) in
+ enumerate(template.source.split(
+ '\n'))])))
+
+ if isinstance(got, byte_string):
+ got = got.decode('utf-8')
+
+ from doctest import OutputChecker
+ checker = OutputChecker()
+
+ if not os.path.exists(output_path):
+ output = template.body
+ else:
+ with open(output_path, 'rb') as f:
+ output = f.read()
+
+ from chameleon.utils import read_xml_encoding
+ from chameleon.utils import detect_encoding
+
+ if template.content_type == 'text/xml':
+ encoding = read_xml_encoding(output) or \
+ template.default_encoding
+ else:
+ content_type, encoding = detect_encoding(
+ output, template.default_encoding)
+
+ want = output.decode(encoding)
+
+ if checker.check_output(want, got, 0) is False:
+ from doctest import Example
+ example = Example(input_path, want)
+ diff = checker.output_difference(
+ example, got, 0)
+ self.fail("(%s) - \n%s\n\nCode:\n%s" % (
+ input_path, diff.rstrip('\n'),
+ template.source.encode('utf-8')))
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py
@@ -0,0 +1,47 @@
+import sys
+
+from unittest import TestCase
+
+
+class TokenizerTest(TestCase):
+ def test_sample_files(self):
+ import os
+ import traceback
+ path = os.path.join(os.path.dirname(__file__), "inputs")
+ for filename in os.listdir(path):
+ if not filename.endswith('.xml'):
+ continue
+ f = open(os.path.join(path, filename), 'rb')
+ source = f.read()
+ f.close()
+
+ from ..utils import read_encoded
+ try:
+ want = read_encoded(source)
+ except UnicodeDecodeError:
+ exc = sys.exc_info()[1]
+ self.fail("%s - %s" % (exc, filename))
+
+ from ..tokenize import iter_xml
+ try:
+ tokens = iter_xml(want)
+ got = "".join(tokens)
+ except:
+ self.fail(traceback.format_exc())
+
+ from doctest import OutputChecker
+ checker = OutputChecker()
+
+ if checker.check_output(want, got, 0) is False:
+ from doctest import Example
+ example = Example(f.name, want)
+ diff = checker.output_difference(
+ example, got, 0)
+ self.fail("(%s) - \n%s" % (f.name, diff))
+
+ def test_token(self):
+ from chameleon.tokenize import Token
+ token = Token("abc", 1)
+
+ self.assertTrue(isinstance(token[1:], Token))
+ self.assertEqual(token[1:].pos, 2)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tokenize.py b/lib/Chameleon-2.9.2/src/chameleon/tokenize.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tokenize.py
@@ -0,0 +1,144 @@
+# http://code.activestate.com/recipes/65125-xml-lexing-shallow-parsing/
+# by Paul Prescod
+# licensed under the PSF License
+#
+# modified to capture all non-overlapping parts of tokens
+
+import re
+
+try:
+ str = unicode
+except NameError:
+ pass
+
+class recollector:
+ def __init__(self):
+ self.res = {}
+
+ def add(self, name, reg ):
+ re.compile(reg) # check that it is valid
+ self.res[name] = reg % self.res
+
+collector = recollector()
+a = collector.add
+
+a("TextSE", "[^<]+")
+a("UntilHyphen", "[^-]*-")
+a("Until2Hyphens", "%(UntilHyphen)s(?:[^-]%(UntilHyphen)s)*-")
+a("CommentCE", "%(Until2Hyphens)s>?")
+a("UntilRSBs", "[^\\]]*](?:[^\\]]+])*]+")
+a("CDATA_CE", "%(UntilRSBs)s(?:[^\\]>]%(UntilRSBs)s)*>" )
+a("S", "[ \\n\\t\\r]+")
+a("Simple", "[^\"'>/]+")
+a("NameStrt", "[A-Za-z_:]|[^\\x00-\\x7F]")
+a("NameChar", "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]")
+a("Name", "(?:%(NameStrt)s)(?:%(NameChar)s)*")
+a("QuoteSE", "\"[^\"]*\"|'[^']*'")
+a("DT_IdentSE" , "%(S)s%(Name)s(?:%(S)s(?:%(Name)s|%(QuoteSE)s))*" )
+a("MarkupDeclCE" , "(?:[^\\]\"'><]+|%(QuoteSE)s)*>" )
+a("S1", "[\\n\\r\\t ]")
+a("UntilQMs", "[^?]*\\?+")
+a("PI_Tail" , "\\?>|%(S1)s%(UntilQMs)s(?:[^>?]%(UntilQMs)s)*>" )
+a("DT_ItemSE",
+ "<(?:!(?:--%(Until2Hyphens)s>|[^-]%(MarkupDeclCE)s)|"
+ "\\?%(Name)s(?:%(PI_Tail)s))|%%%(Name)s;|%(S)s"
+)
+a("DocTypeCE" ,
+"%(DT_IdentSE)s(?:%(S)s)?(?:\\[(?:%(DT_ItemSE)s)*](?:%(S)s)?)?>?" )
+a("DeclCE",
+ "--(?:%(CommentCE)s)?|\\[CDATA\\[(?:%(CDATA_CE)s)?|"
+ "DOCTYPE(?:%(DocTypeCE)s)?")
+a("PI_CE", "%(Name)s(?:%(PI_Tail)s)?")
+a("EndTagCE", "%(Name)s(?:%(S)s)?>?")
+a("AttValSE", "\"[^\"]*\"|'[^']*'")
+a("ElemTagCE",
+ "(%(Name)s)(?:(%(S)s)(%(Name)s)(((?:%(S)s)?=(?:%(S)s)?)"
+ "(?:%(AttValSE)s|%(Simple)s)|(?!(?:%(S)s)?=)))*(?:%(S)s)?(/?>)?")
+a("MarkupSPE",
+ "<(?:!(?:%(DeclCE)s)?|"
+ "\\?(?:%(PI_CE)s)?|/(?:%(EndTagCE)s)?|(?:%(ElemTagCE)s)?)")
+a("XML_SPE", "%(TextSE)s|%(MarkupSPE)s")
+a("XML_MARKUP_ONLY_SPE", "%(MarkupSPE)s")
+a("ElemTagSPE", "<|%(Name)s")
+
+re_xml_spe = re.compile(collector.res['XML_SPE'])
+re_markup_only_spe = re.compile(collector.res['XML_MARKUP_ONLY_SPE'])
+
+
+def iter_xml(body, filename=None):
+ for match in re_xml_spe.finditer(body):
+ string = match.group()
+ pos = match.start()
+ yield Token(string, pos, body, filename)
+
+
+def iter_text(body, filename=None):
+ yield Token(body, 0, body, filename)
+
+
+class Token(str):
+ __slots__ = "pos", "source", "filename"
+
+ def __new__(cls, string, pos=0, source=None, filename=None):
+ inst = str.__new__(cls, string)
+ inst.pos = pos
+ inst.source = source
+ inst.filename = filename or ""
+ return inst
+
+ def __getslice__(self, i, j):
+ slice = str.__getslice__(self, i, j)
+ return Token(slice, self.pos + i, self.source, self.filename)
+
+ def __getitem__(self, index):
+ s = str.__getitem__(self, index)
+ if isinstance(index, slice):
+ return Token(
+ s, self.pos + (index.start or 0), self.source, self.filename)
+ return s
+
+ def __add__(self, other):
+ if other is None:
+ return self
+
+ return Token(
+ str.__add__(self, other), self.pos, self.source, self.filename)
+
+ def __eq__(self, other):
+ return str.__eq__(self, other)
+
+ def __hash__(self):
+ return str.__hash__(self)
+
+ def replace(self, *args):
+ s = str.replace(self, *args)
+ return Token(s, self.pos, self.source, self.filename)
+
+ def split(self, *args):
+ l = str.split(self, *args)
+ pos = self.pos
+ for i, s in enumerate(l):
+ l[i] = Token(s, pos, self.source, self.filename)
+ pos += len(s)
+ return l
+
+ def strip(self, *args):
+ return self.lstrip(*args).rstrip(*args)
+
+ def lstrip(self, *args):
+ s = str.lstrip(self, *args)
+ return Token(
+ s, self.pos + len(self) - len(s), self.source, self.filename)
+
+ def rstrip(self, *args):
+ s = str.rstrip(self, *args)
+ return Token(s, self.pos, self.source, self.filename)
+
+ @property
+ def location(self):
+ if self.source is None:
+ return 0, self.pos
+
+ body = self.source[:self.pos]
+ line = body.count('\n')
+ return line + 1, self.pos - body.rfind('\n', 0) - 1
diff --git a/lib/Chameleon-2.9.2/src/chameleon/utils.py b/lib/Chameleon-2.9.2/src/chameleon/utils.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/utils.py
@@ -0,0 +1,429 @@
+import os
+import re
+import sys
+import codecs
+import logging
+
+from copy import copy
+
+version = sys.version_info[:3]
+
+try:
+ import ast as _ast
+except ImportError:
+ from chameleon import ast24 as _ast
+
+
+class ASTProxy(object):
+ aliases = {
+ # Python 3.3
+ 'TryExcept': 'Try',
+ 'TryFinally': 'Try',
+ }
+
+ def __getattr__(self, name):
+ return _ast.__dict__.get(name) or getattr(_ast, self.aliases[name])
+
+
+ast = ASTProxy()
+
+log = logging.getLogger('chameleon.utils')
+
+# Python 2
+if version < (3, 0, 0):
+ import htmlentitydefs
+ import __builtin__ as builtins
+
+ from .py25 import raise_with_traceback
+
+ chr = unichr
+ native_string = str
+ decode_string = unicode
+ encode_string = str
+ unicode_string = unicode
+ string_type = basestring
+ byte_string = str
+
+ def safe_native(s, encoding='utf-8'):
+ if not isinstance(s, unicode):
+ s = decode_string(s, encoding, 'replace')
+
+ return s.encode(encoding)
+
+# Python 3
+else:
+ from html import entities as htmlentitydefs
+ import builtins
+
+ byte_string = bytes
+ string_type = str
+ native_string = str
+ decode_string = bytes.decode
+ encode_string = lambda s: bytes(s, 'utf-8')
+ unicode_string = str
+
+ def safe_native(s, encoding='utf-8'):
+ if not isinstance(s, str):
+ s = decode_string(s, encoding, 'replace')
+
+ return s
+
+ def raise_with_traceback(exc, tb):
+ exc.__traceback__ = tb
+ raise exc
+
+def text_(s, encoding='latin-1', errors='strict'):
+ """ If ``s`` is an instance of ``byte_string``, return
+ ``s.decode(encoding, errors)``, otherwise return ``s``"""
+ if isinstance(s, byte_string):
+ return s.decode(encoding, errors)
+ return s
+
+entity_re = re.compile(r'&(#?)(x?)(\d{1,5}|\w{1,8});')
+
+module_cache = {}
+
+xml_prefixes = (
+ (codecs.BOM_UTF8, 'utf-8-sig'),
+ (codecs.BOM_UTF16_BE, 'utf-16-be'),
+ (codecs.BOM_UTF16_LE, 'utf-16-le'),
+ (codecs.BOM_UTF16, 'utf-16'),
+ (codecs.BOM_UTF32_BE, 'utf-32-be'),
+ (codecs.BOM_UTF32_LE, 'utf-32-le'),
+ (codecs.BOM_UTF32, 'utf-32'),
+ )
+
+
+def _has_encoding(encoding):
+ try:
+ "".encode(encoding)
+ except LookupError:
+ return False
+ else:
+ return True
+
+
+# Precomputed prefix table
+_xml_prefixes = tuple(
+ (bom, str('<?xml').encode(encoding), encoding)
+ for bom, encoding in reversed(xml_prefixes)
+ if _has_encoding(encoding)
+ )
+
+_xml_decl = encode_string("<?xml")
+
+RE_META = re.compile(
+ r'\s*<meta\s+http-equiv=["\']?Content-Type["\']?'
+ r'\s+content=["\']?([^;]+);\s*charset=([^"\']+)["\']?\s*/?\s*>\s*',
+ re.IGNORECASE
+ )
+
+RE_ENCODING = re.compile(
+ r'encoding\s*=\s*(?:"|\')(?P<encoding>[\w\-]+)(?:"|\')'.encode('ascii'),
+ re.IGNORECASE
+ )
+
+
+def read_encoded(data):
+ return read_bytes(data, "utf-8")[0]
+
+
+def read_bytes(body, default_encoding):
+ for bom, prefix, encoding in _xml_prefixes:
+ if body.startswith(bom):
+ document = body.decode(encoding)
+ return document, encoding, \
+ "text/xml" if document.startswith("<?xml") else None
+
+ if prefix != encode_string('<?xml') and body.startswith(prefix):
+ return body.decode(encoding), encoding, "text/xml"
+
+ if body.startswith(_xml_decl):
+ content_type = "text/xml"
+
+ encoding = read_xml_encoding(body) or default_encoding
+ else:
+ content_type, encoding = detect_encoding(body, default_encoding)
+
+ return body.decode(encoding), encoding, content_type
+
+
+def detect_encoding(body, default_encoding):
+ if not isinstance(body, str):
+ body = body.decode('ascii', 'ignore')
+
+ match = RE_META.search(body)
+ if match is not None:
+ return match.groups()
+
+ return None, default_encoding
+
+
+def read_xml_encoding(body):
+ if body.startswith('<?xml'.encode('ascii')):
+ match = RE_ENCODING.search(body)
+ if match is not None:
+ return match.group('encoding').decode('ascii')
+
+
+def mangle(filename):
+ """Mangles template filename into top-level Python module name.
+
+ >>> mangle('hello_world.pt')
+ 'hello_world'
+
+ >>> mangle('foo.bar.baz.pt')
+ 'foo_bar_baz'
+
+ >>> mangle('foo-bar-baz.pt')
+ 'foo_bar_baz'
+
+ """
+
+ base, ext = os.path.splitext(filename)
+ return base.replace('.', '_').replace('-', '_')
+
+
+def char2entity(c):
+ cp = ord(c)
+ name = htmlentitydefs.codepoint2name.get(cp)
+ return '&%s;' % name if name is not None else '&#%d;' % cp
+
+
+def substitute_entity(match, n2cp=htmlentitydefs.name2codepoint):
+ ent = match.group(3)
+
+ if match.group(1) == "#":
+ if match.group(2) == '':
+ return chr(int(ent))
+ elif match.group(2) == 'x':
+ return chr(int('0x' + ent, 16))
+ else:
+ cp = n2cp.get(ent)
+
+ if cp:
+ return chr(cp)
+ else:
+ return match.group()
+
+
+def create_formatted_exception(exc, cls, formatter):
+ try:
+ try:
+ new = type(cls.__name__, (cls, Exception), {
+ '__str__': formatter,
+ '__new__': BaseException.__new__,
+ '__module__': cls.__module__,
+ })
+ except TypeError:
+ new = cls
+
+ try:
+ inst = BaseException.__new__(new)
+ except TypeError:
+ inst = cls.__new__(new)
+
+ BaseException.__init__(inst, *exc.args)
+ inst.__dict__ = exc.__dict__
+
+ return inst
+ except ValueError:
+ name = type(exc).__name__
+ log.warn("Unable to copy exception of type '%s'." % name)
+ raise TypeError(exc)
+
+
+def unescape(string):
+ for name in ('lt', 'gt', 'quot'):
+ cp = htmlentitydefs.name2codepoint[name]
+ string = string.replace('&%s;' % name, chr(cp))
+
+ return string
+
+
+_concat = unicode_string("").join
+
+
+def join(stream):
+ """Concatenate stream.
+
+ >>> print(join(('Hello', ' ', 'world')))
+ Hello world
+
+ >>> join(('Hello', 0))
+ Traceback (most recent call last):
+ ...
+ TypeError: ... expected ...
+
+ """
+
+ try:
+ return _concat(stream)
+ except:
+ # Loop through stream and coerce each element into unicode;
+ # this should raise an exception
+ for element in stream:
+ unicode_string(element)
+
+ # In case it didn't, re-raise the original exception
+ raise
+
+
+def decode_htmlentities(string):
+ """
+ >>> native_string(decode_htmlentities('&'))
+ '&'
+
+ """
+
+ decoded = entity_re.subn(substitute_entity, string)[0]
+
+ # preserve input token data
+ return string.replace(string, decoded)
+
+
+# Taken from zope.dottedname
+def _resolve_dotted(name, module=None):
+ name = name.split('.')
+ if not name[0]:
+ if module is None:
+ raise ValueError("relative name without base module")
+ module = module.split('.')
+ name.pop(0)
+ while not name[0]:
+ module.pop()
+ name.pop(0)
+ name = module + name
+
+ used = name.pop(0)
+ found = __import__(used)
+ for n in name:
+ used += '.' + n
+ try:
+ found = getattr(found, n)
+ except AttributeError:
+ __import__(used)
+ found = getattr(found, n)
+
+ return found
+
+
+def resolve_dotted(dotted):
+ if not dotted in module_cache:
+ resolved = _resolve_dotted(dotted)
+ module_cache[dotted] = resolved
+ return module_cache[dotted]
+
+
+def limit_string(s, max_length=53):
+ if len(s) > max_length:
+ return s[:max_length - 3] + '...'
+
+ return s
+
+
+def format_kwargs(kwargs):
+ items = []
+ for name, value in kwargs.items():
+ if isinstance(value, string_type):
+ short = limit_string(value)
+ items.append((name, short.replace('\n', '\\n')))
+ elif isinstance(value, (int, float)):
+ items.append((name, value))
+ elif isinstance(value, dict):
+ items.append((name, '{...} (%d)' % len(value)))
+ else:
+ items.append((name,
+ "<%s %s at %s>" % (
+ type(value).__name__,
+ getattr(value, '__name__', "-"),
+ hex(abs(id(value))))))
+
+ return ["%s: %s" % item for item in items]
+
+
+class callablestr(str):
+ __slots__ = ()
+
+ def __call__(self):
+ return self
+
+
+class callableint(int):
+ __slots__ = ()
+
+ def __call__(self):
+ return self
+
+
+class descriptorstr(object):
+ __slots__ = "function", "__name__"
+
+ def __init__(self, function):
+ self.function = function
+ self.__name__ = function.__name__
+
+ def __get__(self, context, cls):
+ return callablestr(self.function(context))
+
+
+class descriptorint(object):
+ __slots__ = "function", "__name__"
+
+ def __init__(self, function):
+ self.function = function
+ self.__name__ = function.__name__
+
+ def __get__(self, context, cls):
+ return callableint(self.function(context))
+
+
+class DebuggingOutputStream(list):
+ def append(self, value):
+ if not isinstance(value, string_type):
+ raise TypeError(value)
+
+ unicode_string(value)
+ list.append(self, value)
+
+
+class Scope(dict):
+ set_local = setLocal = dict.__setitem__
+
+ __slots__ = "set_global",
+
+ def __new__(cls, *args):
+ inst = dict.__new__(cls, *args)
+ inst.set_global = inst.__setitem__
+ return inst
+
+ def __getitem__(self, key):
+ try:
+ return dict.__getitem__(self, key)
+ except KeyError:
+ raise NameError(key)
+
+ @property
+ def vars(self):
+ return self
+
+ def copy(self):
+ inst = Scope(self)
+ inst.set_global = self.set_global
+ return inst
+
+
+class ListDictProxy(object):
+ def __init__(self, l):
+ self._l = l
+
+ def get(self, key):
+ return self._l[-1].get(key)
+
+
+class Markup(unicode_string):
+ def __html__(self):
+ return unicode_string(self)
+
+ def __repr__(self):
+ return "s'%s'" % self.s
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py
@@ -0,0 +1,1 @@
+#
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py
@@ -0,0 +1,30 @@
+from chameleon.loader import TemplateLoader as BaseLoader
+from chameleon.zpt import template
+
+
+class TemplateLoader(BaseLoader):
+ formats = {
+ "xml": template.PageTemplateFile,
+ "text": template.PageTextTemplateFile,
+ }
+
+ default_format = "xml"
+
+ def __init__(self, *args, **kwargs):
+ formats = kwargs.pop('formats', None)
+ if formats is not None:
+ self.formats = formats
+
+ super(TemplateLoader, self).__init__(*args, **kwargs)
+
+ def load(self, filename, format=None):
+ """Load and return a template file.
+
+ The format parameter determines will parse the file. Valid
+ options are `xml` and `text`.
+ """
+
+ cls = self.formats[format or self.default_format]
+ return super(TemplateLoader, self).load(filename, cls)
+
+ __getitem__ = load
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/program.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/program.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/program.py
@@ -0,0 +1,751 @@
+import re
+
+try:
+ import ast
+except ImportError:
+ from chameleon import ast24 as ast
+
+try:
+ str = unicode
+except NameError:
+ long = int
+
+from functools import partial
+from copy import copy
+
+from ..program import ElementProgram
+
+from ..namespaces import XML_NS
+from ..namespaces import XMLNS_NS
+from ..namespaces import I18N_NS as I18N
+from ..namespaces import TAL_NS as TAL
+from ..namespaces import METAL_NS as METAL
+from ..namespaces import META_NS as META
+
+from ..astutil import Static
+from ..astutil import parse
+from ..astutil import marker
+
+from .. import tal
+from .. import metal
+from .. import i18n
+from .. import nodes
+
+from ..exc import LanguageError
+from ..exc import ParseError
+from ..exc import CompilationError
+
+from ..utils import decode_htmlentities
+
+try:
+ str = unicode
+except NameError:
+ long = int
+
+
+missing = object()
+
+re_trim = re.compile(r'($\s+|\s+^)', re.MULTILINE)
+
+def skip(node):
+ return node
+
+
+def wrap(node, *wrappers):
+ for wrapper in reversed(wrappers):
+ node = wrapper(node)
+ return node
+
+
+def validate_attributes(attributes, namespace, whitelist):
+ for ns, name in attributes:
+ if ns == namespace and name not in whitelist:
+ raise CompilationError(
+ "Bad attribute for namespace '%s'" % ns, name
+ )
+
+
+class MacroProgram(ElementProgram):
+ """Visitor class that generates a program for the ZPT language."""
+
+ DEFAULT_NAMESPACES = {
+ 'xmlns': XMLNS_NS,
+ 'xml': XML_NS,
+ 'tal': TAL,
+ 'metal': METAL,
+ 'i18n': I18N,
+ 'meta': META,
+ }
+
+ DROP_NS = TAL, METAL, I18N, META
+
+ VARIABLE_BLACKLIST = "default", "repeat", "nothing", \
+ "convert", "decode", "translate"
+
+ _interpolation_enabled = True
+ _whitespace = "\n"
+ _last = ""
+
+ # Macro name (always trivial for a macro program)
+ name = None
+
+ # This default marker value has the semantics that if an
+ # expression evaluates to that value, the expression default value
+ # is returned. For an attribute, if there is no default, this
+ # means that the attribute is dropped.
+ default_marker = None
+
+ # Escape mode (true value means XML-escape)
+ escape = True
+
+ # Attributes which should have boolean behavior (on true, the
+ # value takes the attribute name, on false, the attribute is
+ # dropped)
+ boolean_attributes = set()
+
+ # If provided, this should be a set of attributes for implicit
+ # translation. Any attribute whose name is included in the set
+ # will be translated even without explicit markup. Note that all
+ # values should be lowercase strings.
+ implicit_i18n_attributes = set()
+
+ # If set, text will be translated even without explicit markup.
+ implicit_i18n_translate = False
+
+ # If set, additional attribute whitespace will be stripped.
+ trim_attribute_space = False
+
+ def __init__(self, *args, **kwargs):
+ # Internal array for switch statements
+ self._switches = []
+
+ # Internal array for current use macro level
+ self._use_macro = []
+
+ # Internal array for current interpolation status
+ self._interpolation = [True]
+
+ # Internal dictionary of macro definitions
+ self._macros = {}
+
+ # Apply default values from **kwargs to self
+ self._pop_defaults(
+ kwargs,
+ 'boolean_attributes',
+ 'default_marker',
+ 'escape',
+ 'implicit_i18n_translate',
+ 'implicit_i18n_attributes',
+ 'trim_attribute_space',
+ )
+
+ super(MacroProgram, self).__init__(*args, **kwargs)
+
+ @property
+ def macros(self):
+ macros = list(self._macros.items())
+ macros.append((None, nodes.Sequence(self.body)))
+
+ return tuple(
+ nodes.Macro(name, [nodes.Context(node)])
+ for name, node in macros
+ )
+
+ def visit_default(self, node):
+ return nodes.Text(node)
+
+ def visit_element(self, start, end, children):
+ ns = start['ns_attrs']
+
+ for (prefix, attr), encoded in tuple(ns.items()):
+ if prefix == TAL:
+ ns[prefix, attr] = decode_htmlentities(encoded)
+
+ # Validate namespace attributes
+ validate_attributes(ns, TAL, tal.WHITELIST)
+ validate_attributes(ns, METAL, metal.WHITELIST)
+ validate_attributes(ns, I18N, i18n.WHITELIST)
+
+ # Check attributes for language errors
+ self._check_attributes(start['namespace'], ns)
+
+ # Remember whitespace for item repetition
+ if self._last is not None:
+ self._whitespace = "\n" + " " * len(self._last.rsplit('\n', 1)[-1])
+
+ # Set element-local whitespace
+ whitespace = self._whitespace
+
+ # Set up switch
+ try:
+ clause = ns[TAL, 'switch']
+ except KeyError:
+ switch = None
+ else:
+ switch = nodes.Value(clause)
+
+ self._switches.append(switch)
+
+ body = []
+
+ # Include macro
+ use_macro = ns.get((METAL, 'use-macro'))
+ extend_macro = ns.get((METAL, 'extend-macro'))
+ if use_macro or extend_macro:
+ slots = []
+ self._use_macro.append(slots)
+
+ if use_macro:
+ inner = nodes.UseExternalMacro(
+ nodes.Value(use_macro), slots, False
+ )
+ else:
+ inner = nodes.UseExternalMacro(
+ nodes.Value(extend_macro), slots, True
+ )
+ # -or- include tag
+ else:
+ content = nodes.Sequence(body)
+
+ # tal:content
+ try:
+ clause = ns[TAL, 'content']
+ except KeyError:
+ pass
+ else:
+ key, value = tal.parse_substitution(clause)
+ xlate = True if ns.get((I18N, 'translate')) == '' else False
+ content = self._make_content_node(value, content, key, xlate)
+
+ if end is None:
+ # Make sure start-tag has opening suffix.
+ start['suffix'] = ">"
+
+ # Explicitly set end-tag.
+ end = {
+ 'prefix': '</',
+ 'name': start['name'],
+ 'space': '',
+ 'suffix': '>'
+ }
+
+ # i18n:translate
+ try:
+ clause = ns[I18N, 'translate']
+ except KeyError:
+ pass
+ else:
+ dynamic = ns.get((TAL, 'content')) or ns.get((TAL, 'replace'))
+
+ if not dynamic:
+ content = nodes.Translate(clause, content)
+
+ # tal:attributes
+ try:
+ clause = ns[TAL, 'attributes']
+ except KeyError:
+ TAL_ATTRIBUTES = {}
+ else:
+ TAL_ATTRIBUTES = tal.parse_attributes(clause)
+
+ # i18n:attributes
+ try:
+ clause = ns[I18N, 'attributes']
+ except KeyError:
+ I18N_ATTRIBUTES = {}
+ else:
+ I18N_ATTRIBUTES = i18n.parse_attributes(clause)
+
+ # Prepare attributes from TAL language
+ prepared = tal.prepare_attributes(
+ start['attrs'], TAL_ATTRIBUTES,
+ I18N_ATTRIBUTES, ns, self.DROP_NS
+ )
+
+ # Create attribute nodes
+ STATIC_ATTRIBUTES = self._create_static_attributes(prepared)
+ ATTRIBUTES = self._create_attributes_nodes(
+ prepared, I18N_ATTRIBUTES
+ )
+
+ # Start- and end nodes
+ start_tag = nodes.Start(
+ start['name'],
+ self._maybe_trim(start['prefix']),
+ self._maybe_trim(start['suffix']),
+ ATTRIBUTES
+ )
+
+ end_tag = nodes.End(
+ end['name'],
+ end['space'],
+ self._maybe_trim(end['prefix']),
+ self._maybe_trim(end['suffix']),
+ ) if end is not None else None
+
+ # tal:omit-tag
+ try:
+ clause = ns[TAL, 'omit-tag']
+ except KeyError:
+ omit = False
+ else:
+ clause = clause.strip()
+
+ if clause == "":
+ omit = True
+ else:
+ expression = nodes.Negate(nodes.Value(clause))
+ omit = expression
+
+ # Wrap start- and end-tags in condition
+ start_tag = nodes.Condition(expression, start_tag)
+
+ if end_tag is not None:
+ end_tag = nodes.Condition(expression, end_tag)
+
+ if omit is True or start['namespace'] in self.DROP_NS:
+ inner = content
+ else:
+ inner = nodes.Element(
+ start_tag,
+ end_tag,
+ content,
+ )
+
+ # Assign static attributes dictionary to "attrs" value
+ inner = nodes.Define(
+ [nodes.Alias(["attrs"], STATIC_ATTRIBUTES)],
+ inner,
+ )
+
+ if omit is not False:
+ inner = nodes.Cache([omit], inner)
+
+ # tal:replace
+ try:
+ clause = ns[TAL, 'replace']
+ except KeyError:
+ pass
+ else:
+ key, value = tal.parse_substitution(clause)
+ xlate = True if ns.get((I18N, 'translate')) == '' else False
+ inner = self._make_content_node(value, inner, key, xlate)
+
+ # metal:define-slot
+ try:
+ clause = ns[METAL, 'define-slot']
+ except KeyError:
+ DEFINE_SLOT = skip
+ else:
+ DEFINE_SLOT = partial(nodes.DefineSlot, clause)
+
+ # tal:define
+ try:
+ clause = ns[TAL, 'define']
+ except KeyError:
+ DEFINE = skip
+ else:
+ defines = tal.parse_defines(clause)
+ if defines is None:
+ raise ParseError("Invalid define syntax.", clause)
+
+ DEFINE = partial(
+ nodes.Define,
+ [nodes.Assignment(
+ names, nodes.Value(expr), context == "local")
+ for (context, names, expr) in defines],
+ )
+
+ # tal:case
+ try:
+ clause = ns[TAL, 'case']
+ except KeyError:
+ CASE = skip
+ else:
+ value = nodes.Value(clause)
+ for switch in reversed(self._switches):
+ if switch is not None:
+ break
+ else:
+ raise LanguageError(
+ "Must define switch on a parent element.", clause
+ )
+
+ CASE = lambda node: nodes.Define(
+ [nodes.Assignment(["default"], switch, True)],
+ nodes.Condition(
+ nodes.Equality(switch, value),
+ node,
+ )
+ )
+
+ # tal:repeat
+ try:
+ clause = ns[TAL, 'repeat']
+ except KeyError:
+ REPEAT = skip
+ else:
+ defines = tal.parse_defines(clause)
+ assert len(defines) == 1
+ context, names, expr = defines[0]
+
+ expression = nodes.Value(expr)
+
+ REPEAT = partial(
+ nodes.Repeat,
+ names,
+ expression,
+ context == "local",
+ whitespace
+ )
+
+ # tal:condition
+ try:
+ clause = ns[TAL, 'condition']
+ except KeyError:
+ CONDITION = skip
+ else:
+ expression = nodes.Value(clause)
+ CONDITION = partial(nodes.Condition, expression)
+
+ # tal:switch
+ if switch is None:
+ SWITCH = skip
+ else:
+ SWITCH = partial(nodes.Cache, [switch])
+
+ # i18n:domain
+ try:
+ clause = ns[I18N, 'domain']
+ except KeyError:
+ DOMAIN = skip
+ else:
+ DOMAIN = partial(nodes.Domain, clause)
+
+ # i18n:name
+ try:
+ clause = ns[I18N, 'name']
+ except KeyError:
+ NAME = skip
+ else:
+ if not clause.strip():
+ NAME = skip
+ else:
+ NAME = partial(nodes.Name, clause)
+
+ # The "slot" node next is the first node level that can serve
+ # as a macro slot
+ slot = wrap(
+ inner,
+ DEFINE_SLOT,
+ DEFINE,
+ CASE,
+ CONDITION,
+ REPEAT,
+ SWITCH,
+ DOMAIN,
+ )
+
+ # metal:fill-slot
+ try:
+ clause = ns[METAL, 'fill-slot']
+ except KeyError:
+ pass
+ else:
+ index = -(1 + int(bool(use_macro or extend_macro)))
+
+ try:
+ slots = self._use_macro[index]
+ except IndexError:
+ raise LanguageError(
+ "Cannot use metal:fill-slot without metal:use-macro.",
+ clause
+ )
+
+ slots = self._use_macro[index]
+ slots.append(nodes.FillSlot(clause, slot))
+
+ # metal:define-macro
+ try:
+ clause = ns[METAL, 'define-macro']
+ except KeyError:
+ pass
+ else:
+ self._macros[clause] = slot
+ slot = nodes.UseInternalMacro(clause)
+
+ slot = wrap(
+ slot,
+ NAME
+ )
+
+ # tal:on-error
+ try:
+ clause = ns[TAL, 'on-error']
+ except KeyError:
+ ON_ERROR = skip
+ else:
+ key, value = tal.parse_substitution(clause)
+ translate = True if ns.get((I18N, 'translate')) == '' else False
+
+ fallback = self._make_content_node(value, None, key, translate)
+
+ if omit is False and start['namespace'] not in self.DROP_NS:
+ start_tag = copy(start_tag)
+
+ start_tag.attributes = filter(
+ lambda attribute: isinstance(attribute, nodes.Attribute) and \
+ isinstance(attribute.expression, ast.Str),
+ start_tag.attributes
+ )
+
+ if end_tag is None:
+ # Make sure start-tag has opening suffix. We don't
+ # allow self-closing element here.
+ start_tag.suffix = ">"
+
+ # Explicitly set end-tag.
+ end_tag = nodes.End(start_tag.name, '', '</', '>',)
+
+ fallback = nodes.Element(
+ start_tag,
+ end_tag,
+ fallback,
+ )
+
+ ON_ERROR = partial(nodes.OnError, fallback, 'error')
+
+ clause = ns.get((META, 'interpolation'))
+ if clause in ('false', 'off'):
+ INTERPOLATION = False
+ elif clause in ('true', 'on'):
+ INTERPOLATION = True
+ elif clause is None:
+ INTERPOLATION = self._interpolation[-1]
+ else:
+ raise LanguageError("Bad interpolation setting.", clause)
+
+ self._interpolation.append(INTERPOLATION)
+
+ # Visit content body
+ for child in children:
+ body.append(self.visit(*child))
+
+ self._switches.pop()
+ self._interpolation.pop()
+
+ if use_macro:
+ self._use_macro.pop()
+
+ return wrap(
+ slot,
+ ON_ERROR
+ )
+
+ def visit_start_tag(self, start):
+ return self.visit_element(start, None, [])
+
+ def visit_cdata(self, node):
+ if not self._interpolation[-1] or not '${' in node:
+ return nodes.Text(node)
+
+ expr = nodes.Substitution(node, ())
+ return nodes.Interpolation(expr, True, False)
+
+ def visit_comment(self, node):
+ if node.startswith('<!--!'):
+ return
+
+ if node.startswith('<!--?'):
+ return nodes.Text('<!--' + node.lstrip('<!-?'))
+
+ if not self._interpolation[-1] or not '${' in node:
+ return nodes.Text(node)
+
+ char_escape = ('&', '<', '>') if self.escape else ()
+ expression = nodes.Substitution(node[4:-3], char_escape)
+
+ return nodes.Sequence(
+ [nodes.Text(node[:4]),
+ nodes.Interpolation(expression, True, False),
+ nodes.Text(node[-3:])
+ ])
+
+ def visit_processing_instruction(self, node):
+ if node['name'] != 'python':
+ text = '<?' + node['name'] + node['text'] + '?>'
+ return self.visit_text(text)
+
+ return nodes.CodeBlock(node['text'])
+
+ def visit_text(self, node):
+ self._last = node
+
+ translation = self.implicit_i18n_translate
+
+ if self._interpolation[-1] and '${' in node:
+ char_escape = ('&', '<', '>') if self.escape else ()
+ expression = nodes.Substitution(node, char_escape)
+ return nodes.Interpolation(expression, True, translation)
+
+ if not translation:
+ return nodes.Text(node)
+
+ seq = []
+ while node:
+ m = re.search('\s+', node)
+ if m is not None:
+ s = m.start()
+ if s:
+ t = node[:s]
+ seq.append(nodes.Translate(t, nodes.Text(t)))
+
+ e = m.end()
+ whitespace = nodes.Text(node[s:e])
+ seq.append(whitespace)
+
+ if e < len(node):
+ node = node[e:]
+ continue
+
+ else:
+ seq.append(nodes.Translate(node, nodes.Text(node)))
+
+ break
+
+ return nodes.Sequence(seq)
+
+ def _pop_defaults(self, kwargs, *attributes):
+ for attribute in attributes:
+ default = getattr(self, attribute)
+ value = kwargs.pop(attribute, default)
+ setattr(self, attribute, value)
+
+ def _check_attributes(self, namespace, ns):
+ if namespace in self.DROP_NS and ns.get((TAL, 'attributes')):
+ raise LanguageError(
+ "Dynamic attributes not allowed on elements of "
+ "the namespace: %s." % namespace,
+ ns[TAL, 'attributes'],
+ )
+
+ script = ns.get((TAL, 'script'))
+ if script is not None:
+ raise LanguageError(
+ "The script attribute is unsupported.", script)
+
+ tal_content = ns.get((TAL, 'content'))
+ if tal_content and ns.get((TAL, 'replace')):
+ raise LanguageError(
+ "You cannot use tal:content and tal:replace at the same time.",
+ tal_content
+ )
+
+ if tal_content and ns.get((I18N, 'translate')):
+ raise LanguageError(
+ "You cannot use tal:content with non-trivial i18n:translate.",
+ tal_content
+ )
+
+ def _make_content_node(self, expression, default, key, translate):
+ value = nodes.Value(expression)
+ char_escape = ('&', '<', '>') if key == 'text' else ()
+ content = nodes.Content(value, char_escape, translate)
+
+ if default is not None:
+ content = nodes.Condition(
+ nodes.Identity(value, marker("default")),
+ default,
+ content,
+ )
+
+ # Cache expression to avoid duplicate evaluation
+ content = nodes.Cache([value], content)
+
+ # Define local marker "default"
+ content = nodes.Define(
+ [nodes.Alias(["default"], marker("default"))],
+ content
+ )
+
+ return content
+
+ def _create_attributes_nodes(self, prepared, I18N_ATTRIBUTES):
+ attributes = []
+
+ for name, text, quote, space, eq, expr in prepared:
+ implicit_i18n = name.lower() in self.implicit_i18n_attributes
+
+ char_escape = ('&', '<', '>', quote)
+
+ # Use a provided default text as the default marker
+ # (aliased to the name ``default``), otherwise use the
+ # program's default marker value.
+ if text is not None:
+ default_marker = ast.Str(s=text)
+ else:
+ default_marker = self.default_marker
+
+ msgid = I18N_ATTRIBUTES.get(name, missing)
+
+ # If (by heuristic) ``text`` contains one or more
+ # interpolation expressions, apply interpolation
+ # substitution to the text
+ if expr is None and text is not None and '${' in text:
+ expr = nodes.Substitution(text, char_escape, None)
+ translation = implicit_i18n and msgid is missing
+ value = nodes.Interpolation(expr, True, translation)
+ default_marker = self.default_marker
+
+ # If the expression is non-trivial, the attribute is
+ # dynamic (computed).
+ elif expr is not None:
+ if name in self.boolean_attributes:
+ value = nodes.Boolean(expr, name)
+ else:
+ if text is not None:
+ default = default_marker
+ else:
+ default = None
+
+ value = nodes.Substitution(expr, char_escape, default)
+
+ # Otherwise, it's a static attribute.
+ else:
+ value = ast.Str(s=text)
+ if msgid is missing and implicit_i18n:
+ msgid = text
+
+ # If translation is required, wrap in a translation
+ # clause
+ if msgid is not missing:
+ value = nodes.Translate(msgid, value)
+
+ space = self._maybe_trim(space)
+ attribute = nodes.Attribute(name, value, quote, eq, space)
+
+ if not isinstance(value, ast.Str):
+ # Always define a ``default`` alias for non-static
+ # expressions.
+ attribute = nodes.Define(
+ [nodes.Alias(["default"], default_marker)],
+ attribute,
+ )
+
+ attributes.append(attribute)
+
+ return attributes
+
+ def _create_static_attributes(self, prepared):
+ static_attrs = {}
+
+ for name, text, quote, space, eq, expr in prepared:
+ static_attrs[name] = text if text is not None else expr
+
+ return Static(parse(repr(static_attrs)).body)
+
+ def _maybe_trim(self, string):
+ if self.trim_attribute_space:
+ return re_trim.sub(" ", string)
+
+ return string
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/template.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/template.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/template.py
@@ -0,0 +1,409 @@
+try:
+ import ast
+except ImportError:
+ from chameleon import ast24 as ast
+
+from functools import partial
+from os.path import dirname
+
+from ..i18n import fast_translate
+from ..tales import PythonExpr
+from ..tales import StringExpr
+from ..tales import NotExpr
+from ..tales import ExistsExpr
+from ..tales import ImportExpr
+from ..tales import ProxyExpr
+from ..tales import StructureExpr
+from ..tales import ExpressionParser
+
+from ..tal import RepeatDict
+
+from ..template import BaseTemplate
+from ..template import BaseTemplateFile
+from ..compiler import ExpressionEngine
+from ..loader import TemplateLoader
+from ..astutil import Builtin
+from ..utils import decode_string
+from ..utils import string_type
+
+from .program import MacroProgram
+
+try:
+ bytes
+except NameError:
+ bytes = str
+
+
+class PageTemplate(BaseTemplate):
+ """Constructor for the page template language.
+
+ Takes a string input as the only positional argument::
+
+ template = PageTemplate("<div>Hello, ${name}.</div>")
+
+ Configuration (keyword arguments):
+
+ ``default_expression``
+
+ Set the default expression type. The default setting is
+ ``python``.
+
+ ``encoding``
+
+ The default text substitution value is a unicode string on
+ Python 2 or simply string on Python 3.
+
+ Pass an encoding to allow encoded byte string input
+ (e.g. UTF-8).
+
+ ``literal_false``
+
+ Attributes are not dropped for a value of ``False``. Instead,
+ the value is coerced to a string.
+
+ This setting exists to provide compatibility with the
+ reference implementation.
+
+ ``boolean_attributes``
+
+ Attributes included in this set are treated as booleans: if a
+ true value is provided, the attribute value is the attribute
+ name, e.g.::
+
+ boolean_attributes = {"selected"}
+
+ If we insert an attribute with the name "selected" and
+ provide a true value, the attribute will be rendered::
+
+ selected="selected"
+
+ If a false attribute is provided (including the empty string),
+ the attribute is dropped.
+
+ The special return value ``default`` drops or inserts the
+ attribute based on the value element attribute value.
+
+ ``translate``
+
+ Use this option to set a translation function.
+
+ Example::
+
+ def translate(msgid, domain=None, mapping=None, default=None, context=None):
+ ...
+ return translation
+
+ Note that if ``target_language`` is provided at render time,
+ the translation function must support this argument.
+
+ ``implicit_i18n_translate``
+
+ Enables implicit translation for text appearing inside
+ elements. Default setting is ``False``.
+
+ While implicit translation does work for text that includes
+ expression interpolation, each expression must be simply a
+ variable name (e.g. ``${foo}``); otherwise, the text will not
+ be marked for translation.
+
+ ``implicit_i18n_attributes``
+
+ Any attribute contained in this set will be marked for
+ implicit translation. Each entry must be a lowercase string.
+
+ Example::
+
+ implicit_i18n_attributes = set(['alt', 'title'])
+
+ ``strict``
+
+ Enabled by default. If disabled, expressions are only required
+ to be valid at evaluation time.
+
+ This setting exists to provide compatibility with the
+ reference implementation which compiles expressions at
+ evaluation time.
+
+ ``trim_attribute_space``
+
+ If set, additional attribute whitespace will be stripped.
+
+ Output is unicode on Python 2 and string on Python 3.
+ """
+
+ expression_types = {
+ 'python': PythonExpr,
+ 'string': StringExpr,
+ 'not': NotExpr,
+ 'exists': ExistsExpr,
+ 'import': ImportExpr,
+ 'structure': StructureExpr,
+ }
+
+ default_expression = 'python'
+
+ translate = staticmethod(fast_translate)
+
+ encoding = None
+
+ boolean_attributes = set()
+
+ literal_false = False
+
+ mode = "xml"
+
+ implicit_i18n_translate = False
+
+ implicit_i18n_attributes = set()
+
+ trim_attribute_space = False
+
+ def __init__(self, body, **config):
+ self.macros = Macros(self)
+ super(PageTemplate, self).__init__(body, **config)
+
+ def __getitem__(self, name):
+ return self.macros[name]
+
+ @property
+ def builtins(self):
+ return self._builtins()
+
+ @property
+ def engine(self):
+ if self.literal_false:
+ default_marker = ast.Str(s="__default__")
+ else:
+ default_marker = Builtin("False")
+
+ return partial(
+ ExpressionEngine,
+ self.expression_parser,
+ default_marker=default_marker,
+ )
+
+ @property
+ def expression_parser(self):
+ return ExpressionParser(self.expression_types, self.default_expression)
+
+ def parse(self, body):
+ if self.literal_false:
+ default_marker = ast.Str(s="__default__")
+ else:
+ default_marker = Builtin("False")
+
+ return MacroProgram(
+ body, self.mode, self.filename,
+ escape=True if self.mode == "xml" else False,
+ default_marker=default_marker,
+ boolean_attributes=self.boolean_attributes,
+ implicit_i18n_translate=self.implicit_i18n_translate,
+ implicit_i18n_attributes=self.implicit_i18n_attributes,
+ trim_attribute_space=self.trim_attribute_space,
+ )
+
+ def render(self, encoding=None, translate=None, **vars):
+ """Render template to string.
+
+ The ``encoding`` and ``translate`` arguments are documented in
+ the template class constructor. If passed to this method, they
+ are used instead of the class defaults.
+
+ Additional arguments:
+
+ ``target_language``
+
+ This argument will be partially applied to the translation
+ function.
+
+ An alternative is thus to simply provide a custom
+ translation function which includes this information or
+ relies on a different mechanism.
+
+ """
+
+ non_trivial_translate = translate is not None
+ translate = translate if non_trivial_translate else self.translate or \
+ type(self).translate
+
+ # Curry language parameter if non-trivial
+ target_language = vars.get('target_language')
+ if target_language is not None:
+ translate = partial(translate, target_language=target_language)
+
+ encoding = encoding if encoding is not None else self.encoding
+ if encoding is not None:
+ txl = translate
+
+ def translate(msgid, **kwargs):
+ if isinstance(msgid, bytes):
+ msgid = decode_string(msgid, encoding)
+ return txl(msgid, **kwargs)
+
+ def decode(inst):
+ return decode_string(inst, encoding, 'ignore')
+ else:
+ decode = decode_string
+
+ setdefault = vars.setdefault
+ setdefault("__translate", translate)
+ setdefault("__convert", translate)
+ setdefault("__decode", decode)
+
+ if non_trivial_translate:
+ vars['translate'] = translate
+
+ # Make sure we have a repeat dictionary
+ if 'repeat' not in vars: vars['repeat'] = RepeatDict({})
+
+ return super(PageTemplate, self).render(**vars)
+
+ def include(self, *args, **kwargs):
+ self.cook_check()
+ self._render(*args, **kwargs)
+
+ def _builtins(self):
+ return {
+ 'template': self,
+ 'macros': self.macros,
+ 'nothing': None,
+ }
+
+
+class PageTemplateFile(PageTemplate, BaseTemplateFile):
+ """File-based constructor.
+
+ Takes a string input as the only positional argument::
+
+ template = PageTemplateFile(absolute_path)
+
+ Note that the file-based template class comes with the expression
+ type ``load`` which loads templates relative to the provided
+ filename.
+
+ Below are listed the configuration arguments specific to
+ file-based templates; see the string-based template class for
+ general options and documentation:
+
+ Configuration (keyword arguments):
+
+ ``loader_class``
+
+ The provided class will be used to create the template loader
+ object. The default implementation supports relative and
+ absolute path specs.
+
+ The class must accept keyword arguments ``search_path``
+ (sequence of paths to search for relative a path spec) and
+ ``default_extension`` (if provided, this should be added to
+ any path spec).
+
+ ``prepend_relative_search_path``
+
+ Inserts the path relative to the provided template file path
+ into the template search path.
+
+ The default setting is ``True``.
+
+ ``search_path``
+
+ If provided, this is used as the search path for the ``load:``
+ expression. It must be a string or an iterable yielding a
+ sequence of strings.
+
+ """
+
+ expression_types = PageTemplate.expression_types.copy()
+ expression_types['load'] = partial(ProxyExpr, '__loader')
+
+ prepend_relative_search_path = True
+
+ def __init__(self, filename, search_path=None, loader_class=TemplateLoader,
+ **config):
+ super(PageTemplateFile, self).__init__(filename, **config)
+
+ if search_path is None:
+ search_path = []
+ else:
+ if isinstance(search_path, string_type):
+ search_path = [search_path]
+ else:
+ search_path = list(search_path)
+
+ # If the flag is set (this is the default), prepend the path
+ # relative to the template file to the search path
+ if self.prepend_relative_search_path:
+ path = dirname(self.filename)
+ search_path.insert(0, path)
+
+ loader = loader_class(search_path=search_path, **config)
+ template_class = type(self)
+
+ # Bind relative template loader instance to the same template
+ # class, providing the same keyword arguments.
+ self._loader = loader.bind(template_class)
+
+ def _builtins(self):
+ d = super(PageTemplateFile, self)._builtins()
+ d['__loader'] = self._loader
+ return d
+
+
+class PageTextTemplate(PageTemplate):
+ """Text-based template class.
+
+ Takes a non-XML input::
+
+ template = PageTextTemplate("Hello, ${name}.")
+
+ This is similar to the standard library class ``string.Template``,
+ but uses the expression engine to substitute variables.
+ """
+
+ mode = "text"
+
+
+class PageTextTemplateFile(PageTemplateFile):
+ """File-based constructor."""
+
+ mode = "text"
+
+ def render(self, **vars):
+ result = super(PageTextTemplateFile, self).render(**vars)
+ return result.encode(self.encoding or 'utf-8')
+
+
+class Macro(object):
+ __slots__ = "include",
+
+ def __init__(self, render):
+ self.include = render
+
+
+class Macros(object):
+ __slots__ = "template",
+
+ def __init__(self, template):
+ self.template = template
+
+ def __getitem__(self, name):
+ name = name.replace('-', '_')
+ self.template.cook_check()
+
+ try:
+ function = getattr(self.template, "_render_%s" % name)
+ except AttributeError:
+ raise KeyError(
+ "Macro does not exist: '%s'." % name)
+
+ return Macro(function)
+
+ @property
+ def names(self):
+ self.template.cook_check()
+
+ result = []
+ for name in self.template.__dict__:
+ if name.startswith('_render_'):
+ result.append(name[8:])
+ return result
diff --git a/lib/Chameleon-2.9.2/src/ordereddict.py b/lib/Chameleon-2.9.2/src/ordereddict.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/ordereddict.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+ def __init__(self, *args, **kwds):
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__end
+ except AttributeError:
+ self.clear()
+ self.update(*args, **kwds)
+
+ def clear(self):
+ self.__end = end = []
+ end += [None, end, end] # sentinel node for doubly linked list
+ self.__map = {} # key --> [key, prev, next]
+ dict.clear(self)
+
+ def __setitem__(self, key, value):
+ if key not in self:
+ end = self.__end
+ curr = end[1]
+ curr[2] = end[1] = self.__map[key] = [key, curr, end]
+ dict.__setitem__(self, key, value)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ key, prev, next = self.__map.pop(key)
+ prev[2] = next
+ next[1] = prev
+
+ def __iter__(self):
+ end = self.__end
+ curr = end[2]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[2]
+
+ def __reversed__(self):
+ end = self.__end
+ curr = end[1]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[1]
+
+ def popitem(self, last=True):
+ if not self:
+ raise KeyError('dictionary is empty')
+ if last:
+ key = reversed(self).next()
+ else:
+ key = iter(self).next()
+ value = self.pop(key)
+ return key, value
+
+ def __reduce__(self):
+ items = [[k, self[k]] for k in self]
+ tmp = self.__map, self.__end
+ del self.__map, self.__end
+ inst_dict = vars(self).copy()
+ self.__map, self.__end = tmp
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def keys(self):
+ return list(self)
+
+ setdefault = DictMixin.setdefault
+ update = DictMixin.update
+ pop = DictMixin.pop
+ values = DictMixin.values
+ items = DictMixin.items
+ iterkeys = DictMixin.iterkeys
+ itervalues = DictMixin.itervalues
+ iteritems = DictMixin.iteritems
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+
+ def copy(self):
+ return self.__class__(self)
+
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+
+ def __eq__(self, other):
+ if isinstance(other, OrderedDict):
+ if len(self) != len(other):
+ return False
+ for p, q in zip(self.items(), other.items()):
+ if p != q:
+ return False
+ return True
+ return dict.__eq__(self, other)
+
+ def __ne__(self, other):
+ return not self == other
diff --git a/lib/Chameleon-2.9.2/tox.ini b/lib/Chameleon-2.9.2/tox.ini
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/tox.ini
@@ -0,0 +1,53 @@
+[tox]
+envlist =
+ py25,py26,py27,py32,pypy,cover
+
+[testenv:py25]
+commands =
+ python setup.py test -q
+deps =
+ ordereddict
+ unittest2
+ distribute
+
+[testenv:py26]
+commands =
+ python setup.py test -q
+deps =
+ ordereddict
+ unittest2
+ distribute
+
+[testenv:py27]
+commands =
+ python setup.py test -q
+deps =
+ distribute
+
+[testenv:py32]
+commands =
+ python setup.py test -q
+deps =
+ distribute
+
+[testenv:pypy]
+commands =
+ python setup.py test -q
+deps =
+ ordereddict
+ unittest2
+ distribute
+
+[testenv:cover]
+basepython =
+ python2.6
+commands =
+ python setup.py nosetests --with-xunit --with-xcoverage
+deps =
+ nose
+ coverage==3.4
+ nosexcover
+ ordereddict
+ unittest2
+ distribute
+
diff --git a/make_perf3.sh b/make_perf3.sh
--- a/make_perf3.sh
+++ b/make_perf3.sh
@@ -31,9 +31,12 @@
${CONVERT} perf.py
# Libraries that are Python 3 compatible as-is.
-SAFE_LIBS_AS_IS="pathlib"
+SAFE_LIBS_AS_IS="Chameleon-2.9.2 pathlib"
# Libraries that work with Python 3 after passing through 2to3.
SAFE_LIBS_TO_TRANSLATE="2to3 mako-0.3.6 mako-0.7.2"
+# Libraries whose source is Python 3 only.
+SAFE_LIBS_PORTED=""
+
mkdir lib
for safe_lib in ${SAFE_LIBS_AS_IS}; do
cp -a "${srcdir}/lib/${safe_lib}" lib/${safe_lib}
@@ -44,6 +47,10 @@
${CONVERT} lib/${safe_lib}
done
+for safe_lib in ${SAFE_LIBS_PORTED}; do
+ cp -a "${srcdir}/lib3/${safe_lib}" lib/${safe_lib}
+done
+
cp -a "${srcdir}/performance" performance
# The 2to3 benchmark looks for sample data to run over behind the
diff --git a/perf.py b/perf.py
--- a/perf.py
+++ b/perf.py
@@ -1329,6 +1329,17 @@
return SimpleBenchmark(MeasureBzrStartup, *args, **kwargs)
+def MeasureChameleon(python, options):
+ bm_path = Relative("performance/bm_chameleon.py", python, options)
+ lib_path = Relative("lib/Chameleon-2.9.2/src", python, options)
+ bm_env = {"PYTHONPATH": lib_path}
+ return MeasureGeneric(python, options, bm_path, bm_env, iteration_scaling=3)
+
+
+def BM_Chameleon(*args, **kwargs):
+ return SimpleBenchmark(MeasureChameleon, *args, **kwargs)
+
+
DJANGO_DIR = Relative("lib/django")
@@ -2082,7 +2093,8 @@
"serialize": ["slowpickle", "slowunpickle", # Not for Python 3
"fastpickle", "fastunpickle",
"json_dump_v2", "json_load"],
- "apps": ["2to3", "html5lib", "rietveld", "spambayes"],
+ "apps": ["2to3", "chameleon", "html5lib", "rietveld",
+ "spambayes"],
"calls": ["call_simple", "call_method", "call_method_slots",
"call_method_unknown"],
"math": ["float", "nbody", "pidigits"],
@@ -2090,7 +2102,7 @@
"logging": ["silent_logging", "simple_logging",
"formatted_logging"],
# Benchmarks natively 2.x- and 3.x-compatible
- "2n3": ["calls", "chaos", "fannkuch", "fastpickle",
+ "2n3": ["calls", "chameleon", "chaos", "fannkuch", "fastpickle",
"fastunpickle", "go", "hexiom2", "json_dump_v2",
"json_load", "math", "logging", "meteor_contest",
"normal_startup", "nqueens", "pathlib", "raytrace",
diff --git a/performance/bm_chameleon.py b/performance/bm_chameleon.py
new file mode 100644
--- /dev/null
+++ b/performance/bm_chameleon.py
@@ -0,0 +1,40 @@
+
+from chameleon import PageTemplate
+
+import compat
+
+BIGTABLE_ZPT = """\
+<table xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<tr tal:repeat="row python: options['table']">
+<td tal:repeat="c python: row.values()">
+<span tal:define="d python: c + 1"
+tal:attributes="class python: 'column-' + %s(d)"
+tal:content="python: d" />
+</td>
+</tr>
+</table>""" % compat.unicode.__name__
+
+def main(n):
+ tmpl = PageTemplate(BIGTABLE_ZPT)
+ options = {'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)]}
+ import time
+ l = []
+ for k in range(n):
+ t0 = time.time()
+ tmpl(options=options)
+ l.append(time.time() - t0)
+ return l
+
+if __name__ == '__main__':
+ import util, optparse
+ parser = optparse.OptionParser(
+ usage="%prog [options]",
+ description="Test the performance of the Go benchmark")
+ util.add_standard_options_to(parser)
+ options, args = parser.parse_args()
+
+ util.run_benchmark(options, options.num_runs, main)
+
+
--
Repository URL: http://hg.python.org/benchmarks
More information about the Python-checkins
mailing list