summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@gmail.com>2012-02-15 09:16:35 -0800
committerJeffrey Yasskin <jyasskin@gmail.com>2012-02-15 09:16:35 -0800
commitab8e7e8e6089c420c0718ed9c851a158712f2833 (patch)
tree58e23442b6d3ee5a95d7f420f57d0df9474c6e1a
parentf1959a6a9866598e3ab9ec464f51a5b11e5075c9 (diff)
downloadpython-lxml-ab8e7e8e6089c420c0718ed9c851a158712f2833.tar.gz
Teach the ElementMaker to add objects of types derived from types it
knows how to handle. This allows it to handle the result of string xpath expressions, which inherit from bytes.
-rw-r--r--src/lxml/builder.py12
-rw-r--r--src/lxml/tests/test_builder.py39
2 files changed, 49 insertions, 2 deletions
diff --git a/src/lxml/builder.py b/src/lxml/builder.py
index c5c25b74..b7fcf406 100644
--- a/src/lxml/builder.py
+++ b/src/lxml/builder.py
@@ -212,12 +212,20 @@ class ElementMaker(object):
for item in children:
if callable(item):
item = item()
- t = get(type(item))
+ for basetype in type(item).__mro__:
+ # __mro__ starts with the type itself, and then
+ # searches all supertypes. If typemap contains
+ # object, this will never fall back to appending an
+ # element.
+ t = get(basetype)
+ if t is not None:
+ break
if t is None:
if ET.iselement(item):
elem.append(item)
continue
- raise TypeError("bad argument type: %r" % item)
+ raise TypeError("bad argument type: %s(%r)" %
+ (type(item).__name__, item))
else:
v = t(elem, item)
if v:
diff --git a/src/lxml/tests/test_builder.py b/src/lxml/tests/test_builder.py
new file mode 100644
index 00000000..b3a31488
--- /dev/null
+++ b/src/lxml/tests/test_builder.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+import unittest
+
+"""
+Tests that ElementMaker works properly.
+"""
+
+import sys, os.path
+from lxml import etree
+from lxml.builder import E
+
+try:
+ import cStringIO
+ StringIO = cStringIO.StringIO
+except ImportError:
+ from io import StringIO
+
+this_dir = os.path.dirname(__file__)
+if this_dir not in sys.path:
+ sys.path.insert(0, this_dir) # needed for Py3
+
+from common_imports import HelperTestCase
+
+class BuilderTestCase(HelperTestCase):
+ etree = etree
+
+ def test_build_from_xpath_result(self):
+ elem = etree.parse(StringIO('<root><node>text</node></root>'))
+ wrapped = E.b(elem.xpath('string(node)'))
+ self.assertEquals(b'<b>text</b>', etree.tostring(wrapped))
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTests([unittest.makeSuite(BuilderTestCase)])
+ return suite
+
+if __name__ == '__main__':
+ print('to test use test.py %s' % __file__)