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_evil_class_lookup(self):
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
182 - def test_class_lookup_type_mismatch(self):
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
223 - def test_attribute_based_lookup(self):
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
239 - def test_custom_lookup(self):
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
256 - def test_custom_lookup_ns_fallback(self):
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
282 - def test_parser_based_lookup(self):
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
306 - def test_class_lookup_reentry(self):
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: # not in the parser 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
334 - def test_lookup_without_fallback(self):
335 class Lookup(etree.CustomElementClassLookup): 336 def __init__(self): 337 # no super call here, so no fallback is set 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
355 -def test_suite():
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