[Python-modules-commits] [python-kajiki] 02/06: Imported Upstream version 0.5.2

Takaki Taniguchi takaki at moszumanska.debian.org
Wed Nov 25 13:59:09 UTC 2015


This is an automated email from the git hooks/post-receive script.

takaki pushed a commit to branch master
in repository python-kajiki.

commit bafb48759269b58e9c3ba682ccb9e4fc4b418621
Author: TANIGUCHI Takaki <takaki at asis.media-as.org>
Date:   Wed Nov 25 22:49:28 2015 +0900

    Imported Upstream version 0.5.2
---
 CHANGES.rst                 |  19 +++++++
 Kajiki.egg-info/PKG-INFO    |  23 ++++++++-
 Kajiki.egg-info/SOURCES.txt |   1 +
 Kajiki.egg-info/pbr.json    |   1 +
 PKG-INFO                    |  23 ++++++++-
 README.rst                  |   2 +
 kajiki/i18n.py              |   7 ++-
 kajiki/ir.py                |  30 +++++------
 kajiki/loader.py            |   8 +--
 kajiki/template.py          |   2 +-
 kajiki/tests/test_xml.py    | 118 ++++++++++++++++++++++++++++++++++++++++++--
 kajiki/version.py           |   4 +-
 kajiki/xml_template.py      |  75 +++++++++++++++++++++++-----
 13 files changed, 272 insertions(+), 41 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index 93fec72..6a0ea50 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,25 @@
 CHANGES
 =======
 
+0.5.2 (2015-10-13)
+------------------
+
+* TranslatableTextNodes are now only generated for non-empty strings
+* ``py:with`` statement now accepts multiple variables separated by semicolon
+* Babel message extractor fixed on Python2
+
+0.5.1 (2015-07-26)
+------------------
+
+* Fix crash on PyPy
+
+0.5.0 (2015-07-25)
+------------------
+
+* CDATA sections created by the user are now properly preserved
+* ``cdata_scripts=False`` option in ``XMLTemplate`` allows disabling automatic CDATA for script and style tags.
+* Autoblocks experimental feature automatically creates blocks from specified tag names.
+
 0.4.4 (2013-09-07)
 ------------------
 
diff --git a/Kajiki.egg-info/PKG-INFO b/Kajiki.egg-info/PKG-INFO
index 1c8efcf..71bcba3 100644
--- a/Kajiki.egg-info/PKG-INFO
+++ b/Kajiki.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Kajiki
-Version: 0.4.4
+Version: 0.5.2
 Summary: Fast XML-based template engine with Genshi syntax and Jinja blocks
 Home-page: https://github.com/nandoflorestan/kajiki
 Author: Nando Florestan
@@ -27,6 +27,8 @@ Description: Kajiki provides fast well-formed XML templates
         Example
         =======
         
+        .. code:: python
+        
             >>> import kajiki
             >>> Template = kajiki.XMLTemplate('''<html>
             ...     <head><title>$title</title></head>
@@ -76,6 +78,25 @@ Description: Kajiki provides fast well-formed XML templates
         CHANGES
         =======
         
+        0.5.2 (2015-10-13)
+        ------------------
+        
+        * TranslatableTextNodes are now only generated for non-empty strings
+        * ``py:with`` statement now accepts multiple variables separated by semicolon
+        * Babel message extractor fixed on Python2
+        
+        0.5.1 (2015-07-26)
+        ------------------
+        
+        * Fix crash on PyPy
+        
+        0.5.0 (2015-07-25)
+        ------------------
+        
+        * CDATA sections created by the user are now properly preserved
+        * ``cdata_scripts=False`` option in ``XMLTemplate`` allows disabling automatic CDATA for script and style tags.
+        * Autoblocks experimental feature automatically creates blocks from specified tag names.
+        
         0.4.4 (2013-09-07)
         ------------------
         
diff --git a/Kajiki.egg-info/SOURCES.txt b/Kajiki.egg-info/SOURCES.txt
index 839d31e..06cd081 100644
--- a/Kajiki.egg-info/SOURCES.txt
+++ b/Kajiki.egg-info/SOURCES.txt
@@ -8,6 +8,7 @@ Kajiki.egg-info/SOURCES.txt
 Kajiki.egg-info/dependency_links.txt
 Kajiki.egg-info/entry_points.txt
 Kajiki.egg-info/not-zip-safe
+Kajiki.egg-info/pbr.json
 Kajiki.egg-info/requires.txt
 Kajiki.egg-info/top_level.txt
 docs/Makefile
diff --git a/Kajiki.egg-info/pbr.json b/Kajiki.egg-info/pbr.json
new file mode 100644
index 0000000..fbb37c4
--- /dev/null
+++ b/Kajiki.egg-info/pbr.json
@@ -0,0 +1 @@
+{"is_release": true, "git_version": "592a738"}
\ No newline at end of file
diff --git a/PKG-INFO b/PKG-INFO
index 1c8efcf..71bcba3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Kajiki
-Version: 0.4.4
+Version: 0.5.2
 Summary: Fast XML-based template engine with Genshi syntax and Jinja blocks
 Home-page: https://github.com/nandoflorestan/kajiki
 Author: Nando Florestan
@@ -27,6 +27,8 @@ Description: Kajiki provides fast well-formed XML templates
         Example
         =======
         
+        .. code:: python
+        
             >>> import kajiki
             >>> Template = kajiki.XMLTemplate('''<html>
             ...     <head><title>$title</title></head>
@@ -76,6 +78,25 @@ Description: Kajiki provides fast well-formed XML templates
         CHANGES
         =======
         
+        0.5.2 (2015-10-13)
+        ------------------
+        
+        * TranslatableTextNodes are now only generated for non-empty strings
+        * ``py:with`` statement now accepts multiple variables separated by semicolon
+        * Babel message extractor fixed on Python2
+        
+        0.5.1 (2015-07-26)
+        ------------------
+        
+        * Fix crash on PyPy
+        
+        0.5.0 (2015-07-25)
+        ------------------
+        
+        * CDATA sections created by the user are now properly preserved
+        * ``cdata_scripts=False`` option in ``XMLTemplate`` allows disabling automatic CDATA for script and style tags.
+        * Autoblocks experimental feature automatically creates blocks from specified tag names.
+        
         0.4.4 (2013-09-07)
         ------------------
         
diff --git a/README.rst b/README.rst
index b96da43..cbb76b4 100644
--- a/README.rst
+++ b/README.rst
@@ -19,6 +19,8 @@ And more features are coming soon; stay tuned!
 Example
 =======
 
+.. code:: python
+
     >>> import kajiki
     >>> Template = kajiki.XMLTemplate('''<html>
     ...     <head><title>$title</title></head>
diff --git a/kajiki/i18n.py b/kajiki/i18n.py
index 0702730..e7d54cc 100644
--- a/kajiki/i18n.py
+++ b/kajiki/i18n.py
@@ -13,7 +13,10 @@ def extract(fileobj, keywords, comment_tags, options):
     '''Babel entry point that extracts translation strings from XML templates.
     '''
     from .xml_template import _Parser, _Compiler, expand
-    doc = _Parser(filename='<string>', source=fileobj.read()).parse()
+    source = fileobj.read()
+    if isinstance(source, bytes):
+        source = source.decode('utf-8')
+    doc = _Parser(filename='<string>', source=source).parse()
     expand(doc)
     compiler = _Compiler(filename='<string>', doc=doc,
                          mode=options.get('mode', 'xml'),
@@ -23,4 +26,4 @@ def extract(fileobj, keywords, comment_tags, options):
         if isinstance(node, TranslatableTextNode):
             if node.text.strip():
                 for line in node.text.split('\n'):
-                    yield (node.lineno, '_',  line, [])
+                    yield (node.lineno, '_', line, [])
diff --git a/kajiki/ir.py b/kajiki/ir.py
index a2785dd..dc0ba42 100644
--- a/kajiki/ir.py
+++ b/kajiki/ir.py
@@ -202,13 +202,13 @@ class WithNode(HierNode):
 
     def __init__(self, vars, *body):
         super(WithNode, self).__init__(body)
-        self.vars_text = vars
-        self.vars = dict(var.split('=', 1)
-                         for var in vars.split(';'))
+        self.vars = dict(var.split('=', 1) for var in vars.split(';'))
+        self.vars_args = ','.join('%s=%s' % v for v in self.vars.items())
 
     def py(self):
         yield self.line(
-            'local.__kj__.push_with(locals(), %s)' % self.vars_text)
+            'local.__kj__.push_with(locals(), %s)' % self.vars_args
+        )
         for k, v in iteritems(self.vars):
             yield self.line('%s = %s' % (k, v))
 
@@ -257,7 +257,7 @@ class IfNode(HierNode):
 
 
 class ElseNode(HierNode):
-    def __init__(self,  *body):
+    def __init__(self, *body):
         super(ElseNode, self).__init__(body)
 
     def py(self):
@@ -410,18 +410,14 @@ class PythonNode(Node):
 def optimize(iter_node):
     last_node = None
     for node in iter_node:
-        if type(node) == TextNode:
-            if (type(last_node) == TextNode
-                    and last_node.guard == node.guard):
-                last_node.text += node.text
-            else:
-                if last_node is not None:
-                    yield last_node
-                last_node = node
-        else:
-            if last_node is not None:
-                yield last_node
-            last_node = node
+        if (type(node) == TextNode and type(last_node) == TextNode
+                and last_node.guard == node.guard):
+            last_node.text += node.text
+            # Erase this node by not yielding it.
+            continue
+        if last_node is not None:
+            yield last_node
+        last_node = node
     if last_node is not None:
         yield last_node
 
diff --git a/kajiki/loader.py b/kajiki/loader.py
index fdee048..935f73c 100644
--- a/kajiki/loader.py
+++ b/kajiki/loader.py
@@ -3,7 +3,6 @@
 from __future__ import (absolute_import, division, print_function,
                         unicode_literals)
 from nine import basestring, itervalues
-import codecs
 import os
 import pkg_resources
 
@@ -42,7 +41,7 @@ class MockLoader(Loader):
 
 class FileLoader(Loader):
     def __init__(self, path, reload=True, force_mode=None,
-                 autoescape_text=False):
+                 autoescape_text=False, xml_autoblocks=None):
         super(FileLoader, self).__init__()
         from kajiki import XMLTemplate, TextTemplate
         if isinstance(path, basestring):
@@ -53,6 +52,7 @@ class FileLoader(Loader):
         self._reload = reload
         self._force_mode = force_mode
         self._autoescape_text = autoescape_text
+        self._xml_autoblocks = xml_autoblocks
         self.extension_map = dict(
             txt=lambda *a, **kw: TextTemplate(
                 autoescape=self._autoescape_text, *a, **kw),
@@ -88,7 +88,9 @@ class FileLoader(Loader):
                 autoescape=self._autoescape_text, *args, **kwargs)
         elif self._force_mode:
             return XMLTemplate(filename=filename,
-                mode=self._force_mode, *args, **kwargs)
+                               mode=self._force_mode,
+                               autoblocks=self._xml_autoblocks,
+                               *args, **kwargs)
         else:
             ext = os.path.splitext(filename)[1][1:]
             return self.extension_map[ext](
diff --git a/kajiki/template.py b/kajiki/template.py
index 33d39ab..d3d6ca1 100644
--- a/kajiki/template.py
+++ b/kajiki/template.py
@@ -153,7 +153,7 @@ class _Template(object):
             # Preserve our tests and Kajiki behaviour across Python versions:
             return uval.replace('&', '&').replace('<', '<') \
                 .replace('>', '>').replace('"', '"')
-                # .replace("'", '''))
+            # .replace("'", '''))
             # Above we do NOT escape the single quote; we don't need it because
             # all HTML attributes are double-quoted in our output.
         else:
diff --git a/kajiki/tests/test_xml.py b/kajiki/tests/test_xml.py
index 9c703bb..bc286a7 100755
--- a/kajiki/tests/test_xml.py
+++ b/kajiki/tests/test_xml.py
@@ -66,12 +66,13 @@ class TestExpand(TestCase):
 
 
 def perform(source, expected_output, context=dict(name='Rick'),
-            mode='xml', is_fragment=True):
-    tpl = XMLTemplate(source, mode=mode, is_fragment=is_fragment)
+            mode='xml', is_fragment=True, cdata_scripts=True):
+    tpl = XMLTemplate(source, mode=mode, is_fragment=is_fragment,
+                      cdata_scripts=cdata_scripts)
     try:
         rsp = tpl(context).render()
         assert isinstance(rsp, str), 'render() must return a unicode string.'
-        assert rsp == expected_output, rsp
+        assert rsp == expected_output, (rsp, expected_output)
     except:
         print('\n' + tpl.py_text)
         raise
@@ -127,6 +128,29 @@ class TestSimple(TestCase):
         perform(src, '<script>/*<![CDATA[*/ Rick /*]]>*/</script>', mode='xml')
         perform(src, '<script> Rick </script>', mode='html')
 
+    def test_CDATA_disabled(self):
+        src = '<script> $name </script>'
+        perform(src, '<script> Rick </script>', mode='xml', cdata_scripts=False)
+        perform(src, '<script> Rick </script>', mode='html', cdata_scripts=False)
+
+    def test_CDATA_escaping(self):
+        src = '''<myxml><data><![CDATA[>ð $name]]></data></myxml>'''
+        perform(src, '<myxml><data><![CDATA[>ð Rick]]></data></myxml>', mode='xml')
+        perform(src, '<myxml><data><![CDATA[>ð Rick]]></data></myxml>', mode='html')
+
+    def test_CDATA_escaping_mixed(self):
+        src = '''<myxml><data><![CDATA[>ð $name]]> ></data></myxml>'''
+        perform(src, '<myxml><data><![CDATA[>ð Rick]]> ></data></myxml>', mode='xml')
+        perform(src, '<myxml><data><![CDATA[>ð Rick]]> ></data></myxml>', mode='html')
+
+    def test_script_commented_CDATA(self):
+        script = 'if (1 < 2) { doc.write("<p>Offen bach</p>"); }\n'
+        src = '<script>/*<![CDATA[*/\n{0}/*]]>*/</script>'.format(script)
+        perform(src, mode='html',
+                expected_output='<script>/**/\n{0}/**/</script>'.format(script))
+        perform(src, '<script>/*<![CDATA[*//**/\n{0}/**//*]]>*/</script>'.format(
+                script), mode='xml')
+
     def test_escape_dollar(self):
         perform('<div>$$</div>', '<div>$</div>')
 
@@ -208,6 +232,18 @@ class TestWith(TestCase):
 <div>foo</div>
 </div>''')
 
+    def test_with_multiple(self):
+        perform('''<div py:with="a='foo';b=3">
+<div>$a - $b</div>
+<div py:with="a=5;b=1">$a - $b</div>
+<div>$a - $b</div>
+</div>''',   '''<div>
+<div>foo - 3</div>
+<div>5 - 1</div>
+<div>foo - 3</div>
+</div>''')
+
+
 
 class TestFunction(TestCase):
     def test_function(self):
@@ -430,6 +466,82 @@ Thanks for the gift!</p>
 Sincerely,<br/><em>Rick</em>
 </div>''', rsp
 
+    def test_autoblocks(self):
+        loader = MockLoader({
+            'parent.html': XMLTemplate('''
+<html py:strip="">
+<head></head>
+<body>
+    <p py:block="body">It was good seeing you last Friday.
+    Thanks for the gift!</p>
+</body>
+</html>'''),
+            'child.html': XMLTemplate('''
+<html>
+<py:extends href="parent.html"/>
+<body><em>Great conference this weekend!</em></body>
+</html>''', autoblocks=['body'])})
+
+        parent = loader.import_('parent.html')
+        rsp = parent().render()
+        assert rsp == '''
+<head/>
+<body>
+    <p>It was good seeing you last Friday.
+    Thanks for the gift!</p>
+</body>
+''', rsp
+
+        child = loader.import_('child.html')
+        rsp = child().render()
+        assert rsp == '''<html>
+
+<head/>
+<body>
+    <em>Great conference this weekend!</em>
+</body>
+
+
+</html>''', rsp
+
+    def test_autoblocks_disabling(self):
+        loader = MockLoader({
+            'parent.html': XMLTemplate('''
+<html py:strip="">
+<head></head>
+<body py:autoblock="False">
+    <p py:block="body">It was good seeing you last Friday.
+    Thanks for the gift!</p>
+</body>
+</html>''', autoblocks=['body']),
+            'child.html': XMLTemplate('''
+<html>
+<py:extends href="parent.html"/>
+<body><em>Great conference this weekend!</em></body>
+</html>''', autoblocks=['body'])})
+
+        parent = loader.import_('parent.html')
+        rsp = parent().render()
+        assert rsp == '''
+<head/>
+<body>
+    <p>It was good seeing you last Friday.
+    Thanks for the gift!</p>
+</body>
+''', rsp
+
+        child = loader.import_('child.html')
+        rsp = child().render()
+        assert rsp == '''<html>
+
+<head/>
+<body>
+    <em>Great conference this weekend!</em>
+</body>
+
+
+</html>''', rsp
+
 
 class TestClosure(TestCase):
     def test(self):
diff --git a/kajiki/version.py b/kajiki/version.py
index d0745a6..5665fa9 100644
--- a/kajiki/version.py
+++ b/kajiki/version.py
@@ -2,5 +2,5 @@
 from __future__ import (absolute_import, division, print_function,
                         unicode_literals)
 
-__version__ = '0.4'
-__release__ = '0.4.4'
+__version__ = '0.5'
+__release__ = '0.5.2'
diff --git a/kajiki/xml_template.py b/kajiki/xml_template.py
index 40bcddc..fcec6c1 100644
--- a/kajiki/xml_template.py
+++ b/kajiki/xml_template.py
@@ -6,7 +6,7 @@ import re
 from codecs import open
 from xml import sax
 from xml.dom import minidom as dom
-from nine import IS_PYTHON2, basestring, str, iteritems
+from nine import IS_PYTHON2, basestring, str, iteritems, native_str
 
 if IS_PYTHON2:
     from cStringIO import StringIO as BytesIO
@@ -26,7 +26,7 @@ impl = dom.getDOMImplementation(' ')
 
 
 def XMLTemplate(source=None, filename=None, mode=None, is_fragment=False,
-                encoding='utf-8'):
+                encoding='utf-8', autoblocks=None, cdata_scripts=True):
     if source is None:
         with open(filename, encoding=encoding) as f:
             source = f.read()  # source is a unicode string
@@ -34,7 +34,8 @@ def XMLTemplate(source=None, filename=None, mode=None, is_fragment=False,
         filename = '<string>'
     doc = _Parser(filename, source).parse()
     expand(doc)
-    compiler = _Compiler(filename, doc, mode=mode, is_fragment=is_fragment)
+    compiler = _Compiler(filename, doc, mode=mode, is_fragment=is_fragment,
+                         autoblocks=autoblocks, cdata_scripts=cdata_scripts)
     ir_ = compiler.compile()
     return template.from_ir(ir_)
 
@@ -48,7 +49,8 @@ def annotate(gen):
 
 
 class _Compiler(object):
-    def __init__(self, filename, doc, mode=None, is_fragment=False):
+    def __init__(self, filename, doc, mode=None, is_fragment=False,
+                 autoblocks=None, cdata_scripts=True):
         self.filename = filename
         self.doc = doc
         self.is_fragment = is_fragment
@@ -56,6 +58,8 @@ class _Compiler(object):
         self.functions['__main__()'] = []
         self.function_lnos = {}
         self.mod_py = []
+        self.autoblocks = autoblocks or []
+        self.cdata_scripts = cdata_scripts
         self.in_def = False
         self.is_child = False
         # The rendering mode is either specified in the *mode* argument,
@@ -100,6 +104,22 @@ class _Compiler(object):
         ir_node.filename = self.filename
         ir_node.lineno = dom_node.lineno
 
+    def _is_autoblock(self, node):
+        if node.tagName not in self.autoblocks:
+            return False
+
+        if node.hasAttribute('py:autoblock'):
+            guard = node.getAttribute('py:autoblock').lower()
+            if guard not in ('false', 'true'):
+                raise ValueError('py:autoblock is evaluated at compile time '
+                                 'and only accepts True/False constants')
+            if guard == 'false':
+                # We throw away the attribute so it doesn't remain in rendered nodes.
+                node.removeAttribute('py:autoblock')
+                return False
+
+        return True
+
     def _compile_node(self, node):
         if isinstance(node, dom.Comment):
             return self._compile_comment(node)
@@ -107,6 +127,10 @@ class _Compiler(object):
             return self._compile_text(node)
         elif isinstance(node, dom.ProcessingInstruction):
             return self._compile_pi(node)
+        elif self._is_autoblock(node):
+            # Set the name of the block equal to the tag itself.
+            node.setAttribute('name', node.tagName)
+            return self._compile_block(node)
         elif node.tagName.startswith('py:'):
             # Handle directives
             compiler = getattr(
@@ -147,20 +171,28 @@ class _Compiler(object):
         else:
             if node.childNodes:
                 yield ir.TextNode('>', guard)
-                if node.tagName in HTML_CDATA_TAGS:
+                if self.cdata_scripts and node.tagName in HTML_CDATA_TAGS:
                     # Special behaviour for <script>, <style> tags:
                     if self.mode == 'xml':  # Start escaping
                         yield ir.TextNode('/*<![CDATA[*/')
                     # Need to unescape the contents of these tags
                     for child in node.childNodes:
+                        # CDATA for scripts and styles are automatically managed.
+                        if getattr(child, '_cdata', False):
+                            continue
                         assert isinstance(child, dom.Text)
                         for x in self._compile_text(child):
-                            x.text = unescape(x.text)
+                            if child.escaped:  # If user declared CDATA no escaping happened.
+                                x.text = unescape(x.text)
                             yield x
                     if self.mode == 'xml':  # Finish escaping
                         yield ir.TextNode('/*]]>*/')
                 else:
                     for cn in node.childNodes:
+                        # Keep CDATA sections around if declared by user
+                        if getattr(cn, '_cdata', False):
+                            yield ir.TextNode(cn.data)
+                            continue
                         for x in self._compile_node(cn):
                             yield x
                 if not (self.mode.startswith('html')
@@ -297,13 +329,22 @@ class _Compiler(object):
                 yield x
 
 
+def make_text_node(text, guard=None):
+    '''Return a TranslatableTextNode if the text is not empty,
+    otherwise a regular TextNode.
+    '''
+    if text.strip():
+        return ir.TranslatableTextNode(text, guard)
+    return ir.TextNode(text, guard)
+
+
 class _TextCompiler(object):
     '''Separates expressions such as ${some_var} from the ordinary text
     around them in the template source and generates ExprNode instances and
     TextNode instances accordingly.
     '''
     def __init__(self, filename, source, lineno,
-                 node_type=ir.TranslatableTextNode, in_html_attr=False):
+                 node_type=make_text_node, in_html_attr=False):
         self.filename = filename
         self.source = source
         self.orig_lineno = lineno
@@ -396,6 +437,7 @@ class _Parser(sax.ContentHandler):
         self._doc._dtd, position, source = extract_dtd(source)
         # Use our own DTD just for XML parsing
         self._source = source[:position] + self.DTD + source[position:]
+        self._cdata_stack = []
 
     def parse(self):
         self._parser = parser = sax.make_parser()
@@ -411,7 +453,7 @@ class _Parser(sax.ContentHandler):
         # So if source is unicode, we pre-encode it:
         # TODO Is this dance really necessary? Can't I just call a function?
         byts = self._source.encode('utf-8')
-        source.setEncoding('utf-8')
+        source.setEncoding(native_str('utf-8'))
         source.setByteStream(BytesIO(byts))
         source.setSystemId(self._filename)
         parser.parse(source)
@@ -434,9 +476,12 @@ class _Parser(sax.ContentHandler):
         assert name == popped.tagName
 
     def characters(self, content):
-        content = sax.saxutils.escape(content)
+        should_escape = not self._cdata_stack
+        if should_escape:
+            content = sax.saxutils.escape(content)
         node = self._doc.createTextNode(content)
         node.lineno = self._parser.getLineNumber()
+        node.escaped = should_escape
         self._els[-1].appendChild(node)
 
     def processingInstruction(self, target, data):
@@ -473,10 +518,18 @@ class _Parser(sax.ContentHandler):
         self._els[-1].appendChild(node)
 
     def startCDATA(self):
-        pass
+        node = self._doc.createTextNode('<![CDATA[')
+        node._cdata = True
+        node.lineno = self._parser.getLineNumber()
+        self._els[-1].appendChild(node)
+        self._cdata_stack.append(self._els[-1])
 
     def endCDATA(self):
-        pass
+        node = self._doc.createTextNode(']]>')
+        node._cdata = True
+        node.lineno = self._parser.getLineNumber()
+        self._els[-1].appendChild(node)
+        self._cdata_stack.pop()
 
     def startDTD(self, name, pubid, sysid):
         self._doc.doctype = impl.createDocumentType(name, pubid, sysid)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-kajiki.git



More information about the Python-modules-commits mailing list