1
2
3 """
4 Tests for different Element class lookup mechanisms.
5 """
6
7
8 import unittest, os.path, sys, gc
9
10 this_dir = os.path.dirname(__file__)
11 if this_dir not in sys.path:
12 sys.path.insert(0, this_dir)
13
14 from common_imports import etree, HelperTestCase, SillyFileLike, fileInTestDir
15 from common_imports import canonicalize, _bytes, _str, BytesIO, StringIO
16
17 xml_str = _bytes('''\
18 <root xmlns="myNS" xmlns:other="otherNS">
19 <c1 a1="A1" a2="A2" other:a3="A3">
20 <c2 a1="C2">0</c2>
21 <c2>1</c2>
22 <other:c2>2</other:c2>
23 </c1>
24 </root>''')
25
26
28 """Basic tests for element proxy behaviour.
29 """
30 etree = etree
31
36
43
53
55 root = etree.XML('<a><b><c/></b></a>')
56 old_elements = set(root.iter())
57 elements = root.iter()
58 del root
59 gc.collect()
60
61 missing = len(old_elements)
62 self.assertEqual(3, missing)
63 for new in elements:
64 for old in old_elements:
65 if old == new:
66 self.assertTrue(old is new)
67 missing -= 1
68 break
69 else:
70 self.assertTrue(False, "element '%s' is missing" % new.tag)
71 self.assertEqual(0, missing)
72
79
90
98
106
107
133
135 class TestElement(etree.ElementBase):
136 FIND_ME = "default element"
137 class TestComment(etree.CommentBase):
138 FIND_ME = "default comment"
139 class TestPI(etree.PIBase):
140 FIND_ME = "default pi"
141
142 parser = etree.XMLParser()
143
144 lookup = etree.ElementDefaultClassLookup(
145 element=TestElement, comment=TestComment, pi=TestPI)
146 parser.set_element_class_lookup(lookup)
147
148 root = etree.XML(_bytes("""<?xml version='1.0'?>
149 <root>
150 <?myPI?>
151 <!-- hi -->
152 </root>
153 """), parser)
154
155 self.assertEqual("default element", root.FIND_ME)
156 self.assertEqual("default pi", root[0].FIND_ME)
157 self.assertEqual("default comment", root[1].FIND_ME)
158
160 class MyLookup(etree.CustomElementClassLookup):
161 def lookup(self, t, d, ns, name):
162 if name == 'none':
163 return None
164 elif name == 'obj':
165 return object()
166 else:
167 return etree.ElementBase
168
169 parser = etree.XMLParser()
170 parser.set_element_class_lookup(MyLookup())
171
172 root = etree.XML(_bytes('<none/>'), parser)
173 self.assertEqual('none', root.tag)
174
175 self.assertRaises(
176 TypeError,
177 etree.XML, _bytes("<obj />"), parser)
178
179 root = etree.XML(_bytes('<root/>'), parser)
180 self.assertEqual('root', root.tag)
181
183 class MyLookup(etree.CustomElementClassLookup):
184 def lookup(self, t, d, ns, name):
185 if t == 'element':
186 if name == 'root':
187 return etree.ElementBase
188 return etree.CommentBase
189 elif t == 'comment':
190 return etree.PIBase
191 elif t == 'PI':
192 return etree.EntityBase
193 elif t == 'entity':
194 return etree.ElementBase
195 else:
196 raise ValueError('got type %s' % t)
197
198 parser = etree.XMLParser(resolve_entities=False)
199 parser.set_element_class_lookup(MyLookup())
200
201 root = etree.XML(_bytes('<root></root>'), parser)
202 self.assertEqual('root', root.tag)
203 self.assertEqual(etree.ElementBase, type(root))
204
205 root = etree.XML(_bytes("<root><test/></root>"), parser)
206 self.assertRaises(TypeError, root.__getitem__, 0)
207
208 root = etree.XML(_bytes("<root><!-- test --></root>"), parser)
209 self.assertRaises(TypeError, root.__getitem__, 0)
210
211 root = etree.XML(_bytes("<root><?test?></root>"), parser)
212 self.assertRaises(TypeError, root.__getitem__, 0)
213
214 root = etree.XML(
215 _bytes('<!DOCTYPE root [<!ENTITY myent "ent">]>'
216 '<root>&myent;</root>'),
217 parser)
218 self.assertRaises(TypeError, root.__getitem__, 0)
219
220 root = etree.XML(_bytes('<root><root/></root>'), parser)
221 self.assertEqual('root', root[0].tag)
222
224 class TestElement(etree.ElementBase):
225 FIND_ME = "attribute_based"
226
227 class_dict = {"A1" : TestElement}
228
229 lookup = etree.AttributeBasedElementClassLookup(
230 "a1", class_dict)
231 etree.set_element_class_lookup(lookup)
232
233 root = etree.XML(xml_str)
234 self.assertFalse(hasattr(root, 'FIND_ME'))
235 self.assertEqual(root[0].FIND_ME,
236 TestElement.FIND_ME)
237 self.assertFalse(hasattr(root[0][0], 'FIND_ME'))
238
240 class TestElement(etree.ElementBase):
241 FIND_ME = "custom"
242
243 class MyLookup(etree.CustomElementClassLookup):
244 def lookup(self, t, d, ns, name):
245 if name == 'c1':
246 return TestElement
247
248 etree.set_element_class_lookup( MyLookup() )
249
250 root = etree.XML(xml_str)
251 self.assertFalse(hasattr(root, 'FIND_ME'))
252 self.assertEqual(root[0].FIND_ME,
253 TestElement.FIND_ME)
254 self.assertFalse(hasattr(root[0][1], 'FIND_ME'))
255
257 class TestElement1(etree.ElementBase):
258 FIND_ME = "custom"
259
260 class TestElement2(etree.ElementBase):
261 FIND_ME = "nsclasses"
262
263 class MyLookup(etree.CustomElementClassLookup):
264 def lookup(self, t, d, ns, name):
265 if name == 'c1':
266 return TestElement1
267
268 lookup = etree.ElementNamespaceClassLookup( MyLookup() )
269 etree.set_element_class_lookup(lookup)
270
271 ns = lookup.get_namespace("otherNS")
272 ns[None] = TestElement2
273
274 root = etree.XML(xml_str)
275 self.assertFalse(hasattr(root, 'FIND_ME'))
276 self.assertEqual(root[0].FIND_ME,
277 TestElement1.FIND_ME)
278 self.assertFalse(hasattr(root[0][1], 'FIND_ME'))
279 self.assertEqual(root[0][-1].FIND_ME,
280 TestElement2.FIND_ME)
281
283 class TestElement(etree.ElementBase):
284 FIND_ME = "parser_based"
285
286 lookup = etree.ParserBasedElementClassLookup()
287 etree.set_element_class_lookup(lookup)
288
289 class MyLookup(etree.CustomElementClassLookup):
290 def lookup(self, t, d, ns, name):
291 return TestElement
292
293 parser = etree.XMLParser()
294 parser.set_element_class_lookup( MyLookup() )
295
296 root = etree.parse(BytesIO(xml_str), parser).getroot()
297 self.assertEqual(root.FIND_ME,
298 TestElement.FIND_ME)
299 self.assertEqual(root[0].FIND_ME,
300 TestElement.FIND_ME)
301
302 root = etree.parse(BytesIO(xml_str)).getroot()
303 self.assertFalse(hasattr(root, 'FIND_ME'))
304 self.assertFalse(hasattr(root[0], 'FIND_ME'))
305
307 XML = self.etree.XML
308
309 class TestElement(etree.ElementBase):
310 FIND_ME = "here"
311
312 root = None
313 class MyLookup(etree.CustomElementClassLookup):
314 el = None
315 def lookup(self, t, d, ns, name):
316 if root is not None:
317 if self.el is None and name == "a":
318 self.el = []
319 self.el.append(root.find(name))
320 return TestElement
321
322 parser = self.etree.XMLParser()
323 parser.set_element_class_lookup(MyLookup())
324
325 root = XML(_bytes('<root><a>A</a><b xmlns="test">B</b></root>'),
326 parser)
327
328 a = root[0]
329 self.assertEqual(a.tag, "a")
330 self.assertEqual(root[0].tag, "a")
331 del a
332 self.assertEqual(root[0].tag, "a")
333
335 class Lookup(etree.CustomElementClassLookup):
336 def __init__(self):
337
338 pass
339
340 def lookup(self, node_type, document, namespace, name):
341 return Foo
342
343 class Foo(etree.ElementBase):
344 def custom(self):
345 return "test"
346
347 parser = self.etree.XMLParser()
348 parser.set_element_class_lookup( Lookup() )
349
350 root = etree.XML('<foo/>', parser)
351
352 self.assertEqual("test", root.custom())
353
354
356 suite = unittest.TestSuite()
357 suite.addTests([unittest.makeSuite(ProxyTestCase)])
358 suite.addTests([unittest.makeSuite(ClassLookupTestCase)])
359 return suite
360
361 if __name__ == '__main__':
362 print('to test use test.py %s' % __file__)
363