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 TestElement(etree.ElementBase):
161 FIND_ME = "default element"
162 class TestComment(etree.CommentBase):
163 FIND_ME = "default comment"
164 class TestPI(etree.PIBase):
165 FIND_ME = "default pi"
166
167 parser = etree.XMLPullParser(events=('start', 'end', 'comment', 'pi'))
168 lookup = etree.ElementDefaultClassLookup(
169 element=TestElement, comment=TestComment, pi=TestPI)
170 parser.set_element_class_lookup(lookup)
171
172 events_seen = []
173
174 def add_events(events):
175 for ev, el in events:
176 events_seen.append((ev, el.FIND_ME))
177
178 parser.feed("""<?xml version='1.0'?>
179 <root>
180 <?myPI?>
181 """)
182 add_events(parser.read_events())
183
184 parser.feed("<!-- hi -->")
185 add_events(parser.read_events())
186
187 parser.feed("</root>")
188 root = parser.close()
189 add_events(parser.read_events())
190
191 self.assertEqual([
192 ('start', "default element"),
193 ('pi', "default pi"),
194 ('comment', "default comment"),
195 ('end', "default element"),
196 ], events_seen)
197
198 self.assertEqual("default element", root.FIND_ME)
199 self.assertEqual("default pi", root[0].FIND_ME)
200 self.assertEqual("default comment", root[1].FIND_ME)
201
203 class MyLookup(etree.CustomElementClassLookup):
204 def lookup(self, t, d, ns, name):
205 if name == 'none':
206 return None
207 elif name == 'obj':
208 return object()
209 else:
210 return etree.ElementBase
211
212 parser = etree.XMLParser()
213 parser.set_element_class_lookup(MyLookup())
214
215 root = etree.XML(_bytes('<none/>'), parser)
216 self.assertEqual('none', root.tag)
217
218 self.assertRaises(
219 TypeError,
220 etree.XML, _bytes("<obj />"), parser)
221
222 root = etree.XML(_bytes('<root/>'), parser)
223 self.assertEqual('root', root.tag)
224
226 class MyLookup(etree.CustomElementClassLookup):
227 def lookup(self, t, d, ns, name):
228 if t == 'element':
229 if name == 'root':
230 return etree.ElementBase
231 return etree.CommentBase
232 elif t == 'comment':
233 return etree.PIBase
234 elif t == 'PI':
235 return etree.EntityBase
236 elif t == 'entity':
237 return etree.ElementBase
238 else:
239 raise ValueError('got type %s' % t)
240
241 parser = etree.XMLParser(resolve_entities=False)
242 parser.set_element_class_lookup(MyLookup())
243
244 root = etree.XML(_bytes('<root></root>'), parser)
245 self.assertEqual('root', root.tag)
246 self.assertEqual(etree.ElementBase, type(root))
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(_bytes("<root><?test?></root>"), parser)
255 self.assertRaises(TypeError, root.__getitem__, 0)
256
257 root = etree.XML(
258 _bytes('<!DOCTYPE root [<!ENTITY myent "ent">]>'
259 '<root>&myent;</root>'),
260 parser)
261 self.assertRaises(TypeError, root.__getitem__, 0)
262
263 root = etree.XML(_bytes('<root><root/></root>'), parser)
264 self.assertEqual('root', root[0].tag)
265
267 class TestElement(etree.ElementBase):
268 FIND_ME = "attribute_based"
269
270 class_dict = {"A1" : TestElement}
271
272 lookup = etree.AttributeBasedElementClassLookup(
273 "a1", class_dict)
274 etree.set_element_class_lookup(lookup)
275
276 root = etree.XML(xml_str)
277 self.assertFalse(hasattr(root, 'FIND_ME'))
278 self.assertEqual(root[0].FIND_ME,
279 TestElement.FIND_ME)
280 self.assertFalse(hasattr(root[0][0], 'FIND_ME'))
281
283 class TestElement(etree.ElementBase):
284 FIND_ME = "custom"
285
286 class MyLookup(etree.CustomElementClassLookup):
287 def lookup(self, t, d, ns, name):
288 if name == 'c1':
289 return TestElement
290
291 etree.set_element_class_lookup( MyLookup() )
292
293 root = etree.XML(xml_str)
294 self.assertFalse(hasattr(root, 'FIND_ME'))
295 self.assertEqual(root[0].FIND_ME,
296 TestElement.FIND_ME)
297 self.assertFalse(hasattr(root[0][1], 'FIND_ME'))
298
300 class TestElement1(etree.ElementBase):
301 FIND_ME = "custom"
302
303 class TestElement2(etree.ElementBase):
304 FIND_ME = "nsclasses"
305
306 class MyLookup(etree.CustomElementClassLookup):
307 def lookup(self, t, d, ns, name):
308 if name == 'c1':
309 return TestElement1
310
311 lookup = etree.ElementNamespaceClassLookup( MyLookup() )
312 etree.set_element_class_lookup(lookup)
313
314 ns = lookup.get_namespace("otherNS")
315 ns[None] = TestElement2
316
317 root = etree.XML(xml_str)
318 self.assertFalse(hasattr(root, 'FIND_ME'))
319 self.assertEqual(root[0].FIND_ME,
320 TestElement1.FIND_ME)
321 self.assertFalse(hasattr(root[0][1], 'FIND_ME'))
322 self.assertEqual(root[0][-1].FIND_ME,
323 TestElement2.FIND_ME)
324
326 class TestElement(etree.ElementBase):
327 FIND_ME = "parser_based"
328
329 lookup = etree.ParserBasedElementClassLookup()
330 etree.set_element_class_lookup(lookup)
331
332 class MyLookup(etree.CustomElementClassLookup):
333 def lookup(self, t, d, ns, name):
334 return TestElement
335
336 parser = etree.XMLParser()
337 parser.set_element_class_lookup( MyLookup() )
338
339 root = etree.parse(BytesIO(xml_str), parser).getroot()
340 self.assertEqual(root.FIND_ME,
341 TestElement.FIND_ME)
342 self.assertEqual(root[0].FIND_ME,
343 TestElement.FIND_ME)
344
345 root = etree.parse(BytesIO(xml_str)).getroot()
346 self.assertFalse(hasattr(root, 'FIND_ME'))
347 self.assertFalse(hasattr(root[0], 'FIND_ME'))
348
350 XML = self.etree.XML
351
352 class TestElement(etree.ElementBase):
353 FIND_ME = "here"
354
355 root = None
356 class MyLookup(etree.CustomElementClassLookup):
357 el = None
358 def lookup(self, t, d, ns, name):
359 if root is not None:
360 if self.el is None and name == "a":
361 self.el = []
362 self.el.append(root.find(name))
363 return TestElement
364
365 parser = self.etree.XMLParser()
366 parser.set_element_class_lookup(MyLookup())
367
368 root = XML(_bytes('<root><a>A</a><b xmlns="test">B</b></root>'),
369 parser)
370
371 a = root[0]
372 self.assertEqual(a.tag, "a")
373 self.assertEqual(root[0].tag, "a")
374 del a
375 self.assertEqual(root[0].tag, "a")
376
378 class Lookup(etree.CustomElementClassLookup):
379 def __init__(self):
380
381 pass
382
383 def lookup(self, node_type, document, namespace, name):
384 return Foo
385
386 class Foo(etree.ElementBase):
387 def custom(self):
388 return "test"
389
390 parser = self.etree.XMLParser()
391 parser.set_element_class_lookup( Lookup() )
392
393 root = etree.XML('<foo/>', parser)
394
395 self.assertEqual("test", root.custom())
396
397
399 suite = unittest.TestSuite()
400 suite.addTests([unittest.makeSuite(ProxyTestCase)])
401 suite.addTests([unittest.makeSuite(ClassLookupTestCase)])
402 return suite
403
404 if __name__ == '__main__':
405 print('to test use test.py %s' % __file__)
406