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