Luke Ross

lxmlmeld

6 releases git clone https://lukeross.name/projects/lxmlmeld.git/

Meld-like templating using lxml.

Commit 8e72deaeba54cb6fbb996097ac49b6d6c4371ba9

Fix bug in deparent()

Committed 27 Jul 2018 by Luke Ross

lxmlmeld/__init__.py

@@ -1,11 +1,10 @@
-import re
 from copy import deepcopy
 from lxml import etree
 
 NS = "http://www.plope.com/software/meld3"
 
 
-class _doctype_dict(object):
+class _DoctypeDict(object):
     def __init__(self, **kwargs):
         self._doctypes = kwargs
 
@@ -34,7 +33,7 @@ class _doctype_dict(object):
         return self._doctypes.get(*args, **kwargs)
 
 
-doctypes = _doctype_dict(
+doctypes = _DoctypeDict(
     html='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" '
          '"http://www.w3.org/TR/html4/loose.dtd">',
     html_strict='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" '
@@ -155,7 +154,7 @@ class Element(etree.ElementBase):
         """
         parent = self.getparent()
         if parent is None:
-            return
+            return None
 
         idx = self.parentindex()
         if isinstance(text, (list, tuple)):
@@ -259,6 +258,8 @@ class Element(etree.ElementBase):
         idx = self.parentindex()
         parent = self.getparent()
         if parent is not None:
+            if self.tail:
+                parent.text = (parent.text or "") + self.tail
             parent.remove(self)
         return idx
 
@@ -310,8 +311,9 @@ class Element(etree.ElementBase):
             try:
                 file.write(ret)
             except AttributeError:
-                with open(file, "eb") as fh:
+                with open(file, "wb") as fh:
                     fh.write(ret)
+            return None
         else:
             return ret
 


setup.py

@@ -16,7 +16,7 @@ setup(
     name="lxmlmeld",
     url="http://lukeross.name/projects/lxmlmeld",
     packages=["lxmlmeld"],
-    version="0.5",
+    version="0.6",
     classifiers=[
         "Development Status :: 4 - Beta",
         "Environment :: Web Environment",


tests/test_calls.py

@@ -1,3 +1,4 @@
+import unittest
 from copy import deepcopy
 from lxml.builder import E
 from unittest import TestCase
@@ -294,3 +295,23 @@ class DeparentTests(TestCase):
             doc.write_xmlstring(declaration=False),
             b'<a/>'
         )
+
+    def test_deparent_preserves_tail(self):
+        doc = parse_xmlstring(
+            "<a xmlns:meld='http://www.plope.com/software/meld3'>atail"
+            "<b meld:id='z'/>btail</a>"
+        )
+        doc.findmeld('z').deparent()
+        self.assertEqual(
+            doc.write_xmlstring(declaration=False),
+            b'<a>atailbtail</a>'
+        )
+        doc.deparent()  # no-op
+        self.assertEqual(
+            doc.write_xmlstring(declaration=False),
+            b'<a>atailbtail</a>'
+        )
+
+
+if __name__ == '__main__':
+    unittest.main()


tests/test_parse_serialise.py

@@ -1,3 +1,4 @@
+import unittest
 from io import BytesIO, StringIO
 from unittest import TestCase
 
@@ -263,3 +264,7 @@ class XHTMLTests(TestCase):
                 self.assertNotIn(absent, serialised_default)
             for txt in (serialised_on, serialised_off, serialised_default):
                 self.assertIn(b"<br /><p></p></body></html>", txt)
+
+
+if __name__ == '__main__':
+    unittest.main()