Package lxml :: Package tests :: Module test_classlookup
[hide private]
[frames] | no frames]

Source Code for Module lxml.tests.test_classlookup

  1  # -*- coding: utf-8 -*- 
  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   
24 -class ProxyTestCase(HelperTestCase):
25 """Basic tests for element proxy behaviour. 26 """ 27 etree = etree 28
29 - def test_proxy_reuse(self):
30 root = etree.XML('<a><b><c/></b></a>') 31 b = root.find('b') 32 self.assertTrue(b is root[0])
33
35 root = etree.XML('<a><b><c/></b></a>') 36 b = root.find('b') 37 self.assertTrue(self.etree.iselement(b)) 38 gc.collect() 39 self.assertTrue(b is root[0])
40
42 root = etree.XML('<a><b><c/></b></a>') 43 b = root.find('b') 44 self.assertTrue(self.etree.iselement(b)) 45 c = b.find('c') 46 self.assertTrue(self.etree.iselement(c)) 47 del root 48 gc.collect() 49 self.assertTrue(b[0] is c)
50
51 - def test_proxy_hashing(self):
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
70 - def test_element_base(self):
71 el = self.etree.ElementBase() 72 self.assertEqual('ElementBase', el.tag) 73 root = self.etree.ElementBase() 74 root.append(el) 75 self.assertEqual('ElementBase', root[0].tag)
76
78 el = self.etree.ElementBase(etree.ElementBase()) 79 self.assertEqual('ElementBase', el.tag) 80 self.assertEqual(1, len(el)) 81 self.assertEqual('ElementBase', el[0].tag) 82 83 root = self.etree.ElementBase() 84 root.append(el) 85 self.assertEqual('ElementBase', root[0].tag) 86 self.assertEqual('ElementBase', root[0][0].tag)
87
88 - def test_comment_base(self):
89 el = self.etree.CommentBase('some text') 90 self.assertEqual(self.etree.Comment, el.tag) 91 self.assertEqual('some text', el.text) 92 root = self.etree.Element('root') 93 root.append(el) 94 self.assertEqual('some text', root[0].text)
95
96 - def test_pi_base(self):
97 el = self.etree.PIBase('the target', 'some text') 98 self.assertEqual(self.etree.ProcessingInstruction, el.tag) 99 self.assertEqual('some text', el.text) 100 root = self.etree.Element('root') 101 root.append(el) 102 self.assertEqual('some text', root[0].text)
103 104
105 -class ClassLookupTestCase(HelperTestCase):
106 """Test cases for different Element class lookup mechanisms. 107 """ 108 etree = etree 109
110 - def tearDown(self):
113
114 - def test_namespace_lookup(self):
115 class TestElement(etree.ElementBase): 116 FIND_ME = "namespace class"
117 118 lookup = etree.ElementNamespaceClassLookup() 119 etree.set_element_class_lookup(lookup) 120 121 ns = lookup.get_namespace("myNS") 122 ns[None] = TestElement 123 124 root = etree.XML(xml_str) 125 self.assertEqual(root.FIND_ME, 126 TestElement.FIND_ME) 127 self.assertEqual(root[0].FIND_ME, 128 TestElement.FIND_ME) 129 self.assertFalse(hasattr(root[0][-1], 'FIND_ME'))
130
131 - def test_default_class_lookup(self):
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
156 - def test_default_class_lookup_pull_parser(self):
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
199 - def test_evil_class_lookup(self):
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
222 - def test_class_lookup_type_mismatch(self):
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
263 - def test_attribute_based_lookup(self):
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
279 - def test_custom_lookup(self):
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
296 - def test_custom_lookup_ns_fallback(self):
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
322 - def test_parser_based_lookup(self):
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
346 - def test_class_lookup_reentry(self):
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: # not in the parser 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
374 - def test_lookup_without_fallback(self):
375 class Lookup(etree.CustomElementClassLookup): 376 def __init__(self): 377 # no super call here, so no fallback is set 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
395 -def test_suite():
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