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  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) # needed for Py3 
 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   
27 -class ProxyTestCase(HelperTestCase):
28 """Basic tests for element proxy behaviour. 29 """ 30 etree = etree 31
32 - def test_proxy_reuse(self):
33 root = etree.XML('<a><b><c/></b></a>') 34 b = root.find('b') 35 self.assertTrue(b is root[0])
36
38 root = etree.XML('<a><b><c/></b></a>') 39 b = root.find('b') 40 self.assertTrue(self.etree.iselement(b)) 41 gc.collect() 42 self.assertTrue(b is root[0])
43
45 root = etree.XML('<a><b><c/></b></a>') 46 b = root.find('b') 47 self.assertTrue(self.etree.iselement(b)) 48 c = b.find('c') 49 self.assertTrue(self.etree.iselement(c)) 50 del root 51 gc.collect() 52 self.assertTrue(b[0] is c)
53
54 - def test_proxy_hashing(self):
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
73 - def test_element_base(self):
74 el = self.etree.ElementBase() 75 self.assertEqual('ElementBase', el.tag) 76 root = self.etree.ElementBase() 77 root.append(el) 78 self.assertEqual('ElementBase', root[0].tag)
79
81 el = self.etree.ElementBase(etree.ElementBase()) 82 self.assertEqual('ElementBase', el.tag) 83 self.assertEqual(1, len(el)) 84 self.assertEqual('ElementBase', el[0].tag) 85 86 root = self.etree.ElementBase() 87 root.append(el) 88 self.assertEqual('ElementBase', root[0].tag) 89 self.assertEqual('ElementBase', root[0][0].tag)
90
91 - def test_comment_base(self):
92 el = self.etree.CommentBase('some text') 93 self.assertEqual(self.etree.Comment, el.tag) 94 self.assertEqual('some text', el.text) 95 root = self.etree.Element('root') 96 root.append(el) 97 self.assertEqual('some text', root[0].text)
98
99 - def test_pi_base(self):
100 el = self.etree.PIBase('the target', 'some text') 101 self.assertEqual(self.etree.ProcessingInstruction, el.tag) 102 self.assertEqual('some text', el.text) 103 root = self.etree.Element('root') 104 root.append(el) 105 self.assertEqual('some text', root[0].text)
106 107
108 -class ClassLookupTestCase(HelperTestCase):
109 """Test cases for different Element class lookup mechanisms. 110 """ 111 etree = etree 112
113 - def tearDown(self):
116
117 - def test_namespace_lookup(self):
118 class TestElement(etree.ElementBase): 119 FIND_ME = "namespace class"
120 121 lookup = etree.ElementNamespaceClassLookup() 122 etree.set_element_class_lookup(lookup) 123 124 ns = lookup.get_namespace("myNS") 125 ns[None] = TestElement 126 127 root = etree.XML(xml_str) 128 self.assertEqual(root.FIND_ME, 129 TestElement.FIND_ME) 130 self.assertEqual(root[0].FIND_ME, 131 TestElement.FIND_ME) 132 self.assertFalse(hasattr(root[0][-1], 'FIND_ME'))
133
134 - def test_default_class_lookup(self):
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
159 - def test_default_class_lookup_pull_parser(self):
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
202 - def test_evil_class_lookup(self):
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
225 - def test_class_lookup_type_mismatch(self):
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
266 - def test_attribute_based_lookup(self):
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
282 - def test_custom_lookup(self):
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
299 - def test_custom_lookup_ns_fallback(self):
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
325 - def test_parser_based_lookup(self):
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
349 - def test_class_lookup_reentry(self):
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: # not in the parser 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
377 - def test_lookup_without_fallback(self):
378 class Lookup(etree.CustomElementClassLookup): 379 def __init__(self): 380 # no super call here, so no fallback is set 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
398 -def test_suite():
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