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

Source Code for Module lxml.tests.test_etree

   1  # -*- coding: utf-8 -*- 
   2   
   3  """ 
   4  Tests specific to the extended etree API 
   5   
   6  Tests that apply to the general ElementTree API should go into 
   7  test_elementtree 
   8  """ 
   9   
  10  import os.path 
  11  import unittest 
  12  import copy 
  13  import sys 
  14  import re 
  15  import gc 
  16  import operator 
  17  import tempfile 
  18  import textwrap 
  19  import zlib 
  20  import gzip 
  21   
  22  this_dir = os.path.dirname(__file__) 
  23  if this_dir not in sys.path: 
  24      sys.path.insert(0, this_dir) # needed for Py3 
  25   
  26  from common_imports import etree, StringIO, BytesIO, HelperTestCase 
  27  from common_imports import fileInTestDir, fileUrlInTestDir, read_file, path2url 
  28  from common_imports import SillyFileLike, LargeFileLikeUnicode, doctest, make_doctest 
  29  from common_imports import canonicalize, sorted, _str, _bytes 
  30   
  31  print("") 
  32  print("TESTED VERSION: %s" % etree.__version__) 
  33  print("    Python:           " + repr(sys.version_info)) 
  34  print("    lxml.etree:       " + repr(etree.LXML_VERSION)) 
  35  print("    libxml used:      " + repr(etree.LIBXML_VERSION)) 
  36  print("    libxml compiled:  " + repr(etree.LIBXML_COMPILED_VERSION)) 
  37  print("    libxslt used:     " + repr(etree.LIBXSLT_VERSION)) 
  38  print("    libxslt compiled: " + repr(etree.LIBXSLT_COMPILED_VERSION)) 
  39  print("") 
  40   
  41  try: 
  42      _unicode = unicode 
  43  except NameError: 
  44      # Python 3 
  45      _unicode = str 
  46   
47 -class ETreeOnlyTestCase(HelperTestCase):
48 """Tests only for etree, not ElementTree""" 49 etree = etree 50
51 - def test_version(self):
52 self.assertTrue(isinstance(etree.__version__, _unicode)) 53 self.assertTrue(isinstance(etree.LXML_VERSION, tuple)) 54 self.assertEqual(len(etree.LXML_VERSION), 4) 55 self.assertTrue(isinstance(etree.LXML_VERSION[0], int)) 56 self.assertTrue(isinstance(etree.LXML_VERSION[1], int)) 57 self.assertTrue(isinstance(etree.LXML_VERSION[2], int)) 58 self.assertTrue(isinstance(etree.LXML_VERSION[3], int)) 59 self.assertTrue(etree.__version__.startswith( 60 str(etree.LXML_VERSION[0])))
61
62 - def test_c_api(self):
63 if hasattr(self.etree, '__pyx_capi__'): 64 # newer Pyrex compatible C-API 65 self.assertTrue(isinstance(self.etree.__pyx_capi__, dict)) 66 self.assertTrue(len(self.etree.__pyx_capi__) > 0) 67 else: 68 # older C-API mechanism 69 self.assertTrue(hasattr(self.etree, '_import_c_api'))
70
71 - def test_element_names(self):
72 Element = self.etree.Element 73 el = Element('name') 74 self.assertEqual(el.tag, 'name') 75 el = Element('{}name') 76 self.assertEqual(el.tag, 'name')
77
78 - def test_element_name_empty(self):
79 Element = self.etree.Element 80 el = Element('name') 81 self.assertRaises(ValueError, Element, '{}') 82 self.assertRaises(ValueError, setattr, el, 'tag', '{}') 83 84 self.assertRaises(ValueError, Element, '{test}') 85 self.assertRaises(ValueError, setattr, el, 'tag', '{test}')
86
87 - def test_element_name_colon(self):
88 Element = self.etree.Element 89 self.assertRaises(ValueError, Element, 'p:name') 90 self.assertRaises(ValueError, Element, '{test}p:name') 91 92 el = Element('name') 93 self.assertRaises(ValueError, setattr, el, 'tag', 'p:name')
94
95 - def test_element_name_quote(self):
96 Element = self.etree.Element 97 self.assertRaises(ValueError, Element, "p'name") 98 self.assertRaises(ValueError, Element, 'p"name') 99 100 self.assertRaises(ValueError, Element, "{test}p'name") 101 self.assertRaises(ValueError, Element, '{test}p"name') 102 103 el = Element('name') 104 self.assertRaises(ValueError, setattr, el, 'tag', "p'name") 105 self.assertRaises(ValueError, setattr, el, 'tag', 'p"name')
106
107 - def test_element_name_space(self):
108 Element = self.etree.Element 109 self.assertRaises(ValueError, Element, ' name ') 110 self.assertRaises(ValueError, Element, 'na me') 111 self.assertRaises(ValueError, Element, '{test} name') 112 113 el = Element('name') 114 self.assertRaises(ValueError, setattr, el, 'tag', ' name ')
115
116 - def test_subelement_name_empty(self):
117 Element = self.etree.Element 118 SubElement = self.etree.SubElement 119 120 el = Element('name') 121 self.assertRaises(ValueError, SubElement, el, '{}') 122 self.assertRaises(ValueError, SubElement, el, '{test}')
123
124 - def test_subelement_name_colon(self):
125 Element = self.etree.Element 126 SubElement = self.etree.SubElement 127 128 el = Element('name') 129 self.assertRaises(ValueError, SubElement, el, 'p:name') 130 self.assertRaises(ValueError, SubElement, el, '{test}p:name')
131
132 - def test_subelement_name_quote(self):
133 Element = self.etree.Element 134 SubElement = self.etree.SubElement 135 136 el = Element('name') 137 self.assertRaises(ValueError, SubElement, el, "p'name") 138 self.assertRaises(ValueError, SubElement, el, "{test}p'name") 139 140 self.assertRaises(ValueError, SubElement, el, 'p"name') 141 self.assertRaises(ValueError, SubElement, el, '{test}p"name')
142
143 - def test_subelement_name_space(self):
144 Element = self.etree.Element 145 SubElement = self.etree.SubElement 146 147 el = Element('name') 148 self.assertRaises(ValueError, SubElement, el, ' name ') 149 self.assertRaises(ValueError, SubElement, el, 'na me') 150 self.assertRaises(ValueError, SubElement, el, '{test} name')
151
153 Element = self.etree.Element 154 SubElement = self.etree.SubElement 155 156 el = Element('name') 157 self.assertRaises(ValueError, SubElement, el, 'name', {'a b c' : 'abc'}) 158 self.assertRaises(ValueError, SubElement, el, 'name', {'a' : 'a\0\n'}) 159 self.assertEqual(0, len(el))
160
161 - def test_qname_empty(self):
162 QName = self.etree.QName 163 self.assertRaises(ValueError, QName, '') 164 self.assertRaises(ValueError, QName, 'test', '')
165
166 - def test_qname_colon(self):
167 QName = self.etree.QName 168 self.assertRaises(ValueError, QName, 'p:name') 169 self.assertRaises(ValueError, QName, 'test', 'p:name')
170
171 - def test_qname_space(self):
172 QName = self.etree.QName 173 self.assertRaises(ValueError, QName, ' name ') 174 self.assertRaises(ValueError, QName, 'na me') 175 self.assertRaises(ValueError, QName, 'test', ' name')
176
178 # ET doesn't have namespace/localname properties on QNames 179 QName = self.etree.QName 180 namespace, localname = 'http://myns', 'a' 181 qname = QName(namespace, localname) 182 self.assertEqual(namespace, qname.namespace) 183 self.assertEqual(localname, qname.localname)
184
185 - def test_qname_element(self):
186 # ET doesn't have namespace/localname properties on QNames 187 QName = self.etree.QName 188 qname1 = QName('http://myns', 'a') 189 a = self.etree.Element(qname1, nsmap={'p' : 'http://myns'}) 190 191 qname2 = QName(a) 192 self.assertEqual(a.tag, qname1.text) 193 self.assertEqual(qname1.text, qname2.text) 194 self.assertEqual(qname1, qname2)
195
196 - def test_qname_text_resolve(self):
197 # ET doesn't resove QNames as text values 198 etree = self.etree 199 qname = etree.QName('http://myns', 'a') 200 a = etree.Element(qname, nsmap={'p' : 'http://myns'}) 201 a.text = qname 202 203 self.assertEqual("p:a", a.text)
204
205 - def test_nsmap_prefix_invalid(self):
206 etree = self.etree 207 self.assertRaises(ValueError, 208 etree.Element, "root", nsmap={'"' : 'testns'}) 209 self.assertRaises(ValueError, 210 etree.Element, "root", nsmap={'&' : 'testns'}) 211 self.assertRaises(ValueError, 212 etree.Element, "root", nsmap={'a:b' : 'testns'})
213
214 - def test_attribute_has_key(self):
215 # ET in Py 3.x has no "attrib.has_key()" method 216 XML = self.etree.XML 217 218 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 219 self.assertEqual( 220 True, root.attrib.has_key('bar')) 221 self.assertEqual( 222 False, root.attrib.has_key('baz')) 223 self.assertEqual( 224 False, root.attrib.has_key('hah')) 225 self.assertEqual( 226 True, 227 root.attrib.has_key('{http://ns.codespeak.net/test}baz'))
228
229 - def test_attribute_set(self):
230 Element = self.etree.Element 231 root = Element("root") 232 root.set("attr", "TEST") 233 self.assertEqual("TEST", root.get("attr"))
234
236 # ElementTree accepts arbitrary attribute values 237 # lxml.etree allows only strings 238 Element = self.etree.Element 239 240 root = Element("root") 241 root.set("attr", "TEST") 242 self.assertEqual("TEST", root.get("attr")) 243 self.assertRaises(TypeError, root.set, "newattr", 5)
244
245 - def test_attrib_and_keywords(self):
246 Element = self.etree.Element 247 248 root = Element("root") 249 root.set("attr", "TEST") 250 self.assertEqual("TEST", root.attrib["attr"]) 251 252 root2 = Element("root2", root.attrib, attr2='TOAST') 253 self.assertEqual("TEST", root2.attrib["attr"]) 254 self.assertEqual("TOAST", root2.attrib["attr2"]) 255 self.assertEqual(None, root.attrib.get("attr2"))
256
257 - def test_attrib_order(self):
258 Element = self.etree.Element 259 260 keys = ["attr%d" % i for i in range(10)] 261 values = ["TEST-%d" % i for i in range(10)] 262 items = list(zip(keys, values)) 263 264 root = Element("root") 265 for key, value in items: 266 root.set(key, value) 267 self.assertEqual(keys, root.attrib.keys()) 268 self.assertEqual(values, root.attrib.values()) 269 270 root2 = Element("root2", root.attrib, 271 attr_99='TOAST-1', attr_98='TOAST-2') 272 self.assertEqual(['attr_98', 'attr_99'] + keys, 273 root2.attrib.keys()) 274 self.assertEqual(['TOAST-2', 'TOAST-1'] + values, 275 root2.attrib.values()) 276 277 self.assertEqual(keys, root.attrib.keys()) 278 self.assertEqual(values, root.attrib.values())
279
280 - def test_attribute_set_invalid(self):
281 # ElementTree accepts arbitrary attribute values 282 # lxml.etree allows only strings 283 Element = self.etree.Element 284 root = Element("root") 285 self.assertRaises(TypeError, root.set, "newattr", 5) 286 self.assertRaises(TypeError, root.set, "newattr", None)
287
288 - def test_strip_attributes(self):
289 XML = self.etree.XML 290 xml = _bytes('<test a="5" b="10" c="20"><x a="4" b="2"/></test>') 291 292 root = XML(xml) 293 self.etree.strip_attributes(root, 'a') 294 self.assertEqual(_bytes('<test b="10" c="20"><x b="2"></x></test>'), 295 self._writeElement(root)) 296 297 root = XML(xml) 298 self.etree.strip_attributes(root, 'b', 'c') 299 self.assertEqual(_bytes('<test a="5"><x a="4"></x></test>'), 300 self._writeElement(root))
301
302 - def test_strip_attributes_ns(self):
303 XML = self.etree.XML 304 xml = _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20" n:a="5"><x a="4" n:b="2"/></test>') 305 306 root = XML(xml) 307 self.etree.strip_attributes(root, 'a') 308 self.assertEqual( 309 _bytes('<test xmlns:n="http://test/ns" b="10" c="20" n:a="5"><x n:b="2"></x></test>'), 310 self._writeElement(root)) 311 312 root = XML(xml) 313 self.etree.strip_attributes(root, '{http://test/ns}a', 'c') 314 self.assertEqual( 315 _bytes('<test xmlns:n="http://test/ns" a="6" b="10"><x a="4" n:b="2"></x></test>'), 316 self._writeElement(root)) 317 318 root = XML(xml) 319 self.etree.strip_attributes(root, '{http://test/ns}*') 320 self.assertEqual( 321 _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20"><x a="4"></x></test>'), 322 self._writeElement(root))
323
324 - def test_strip_elements(self):
325 XML = self.etree.XML 326 xml = _bytes('<test><a><b><c/></b></a><x><a><b/><c/></a></x></test>') 327 328 root = XML(xml) 329 self.etree.strip_elements(root, 'a') 330 self.assertEqual(_bytes('<test><x></x></test>'), 331 self._writeElement(root)) 332 333 root = XML(xml) 334 self.etree.strip_elements(root, 'b', 'c', 'X', 'Y', 'Z') 335 self.assertEqual(_bytes('<test><a></a><x><a></a></x></test>'), 336 self._writeElement(root)) 337 338 root = XML(xml) 339 self.etree.strip_elements(root, 'c') 340 self.assertEqual(_bytes('<test><a><b></b></a><x><a><b></b></a></x></test>'), 341 self._writeElement(root))
342
343 - def test_strip_elements_ns(self):
344 XML = self.etree.XML 345 xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>C</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>') 346 347 root = XML(xml) 348 self.etree.strip_elements(root, 'a') 349 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X</x>XT</test>'), 350 self._writeElement(root)) 351 352 root = XML(xml) 353 self.etree.strip_elements(root, '{urn:a}b', 'c') 354 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 355 self._writeElement(root)) 356 357 root = XML(xml) 358 self.etree.strip_elements(root, '{urn:a}*', 'c') 359 self.assertEqual(_bytes('<test>TEST<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 360 self._writeElement(root)) 361 362 root = XML(xml) 363 self.etree.strip_elements(root, '{urn:a}*', 'c', with_tail=False) 364 self.assertEqual(_bytes('<test>TESTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 365 self._writeElement(root))
366
367 - def test_strip_tags(self):
368 XML = self.etree.XML 369 xml = _bytes('<test>TEST<a>A<b>B<c/>CT</b>BT</a>AT<x>X<a>A<b/>BT<c/>CT</a>AT</x>XT</test>') 370 371 root = XML(xml) 372 self.etree.strip_tags(root, 'a') 373 self.assertEqual(_bytes('<test>TESTA<b>B<c></c>CT</b>BTAT<x>XA<b></b>BT<c></c>CTAT</x>XT</test>'), 374 self._writeElement(root)) 375 376 root = XML(xml) 377 self.etree.strip_tags(root, 'b', 'c', 'X', 'Y', 'Z') 378 self.assertEqual(_bytes('<test>TEST<a>ABCTBT</a>AT<x>X<a>ABTCT</a>AT</x>XT</test>'), 379 self._writeElement(root)) 380 381 root = XML(xml) 382 self.etree.strip_tags(root, 'c') 383 self.assertEqual(_bytes('<test>TEST<a>A<b>BCT</b>BT</a>AT<x>X<a>A<b></b>BTCT</a>AT</x>XT</test>'), 384 self._writeElement(root))
385
386 - def test_strip_tags_pi_comment(self):
387 XML = self.etree.XML 388 PI = self.etree.ProcessingInstruction 389 Comment = self.etree.Comment 390 xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>') 391 392 root = XML(xml) 393 self.etree.strip_tags(root, PI) 394 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->\n<?PI1?>'), 395 self._writeElement(root)) 396 397 root = XML(xml) 398 self.etree.strip_tags(root, Comment) 399 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT<?PI2?></test>\n<!--comment3-->\n<?PI1?>'), 400 self._writeElement(root)) 401 402 root = XML(xml) 403 self.etree.strip_tags(root, PI, Comment) 404 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'), 405 self._writeElement(root)) 406 407 root = XML(xml) 408 self.etree.strip_tags(root, Comment, PI) 409 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'), 410 self._writeElement(root))
411
413 XML = self.etree.XML 414 ElementTree = self.etree.ElementTree 415 PI = self.etree.ProcessingInstruction 416 Comment = self.etree.Comment 417 xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>') 418 419 root = XML(xml) 420 self.etree.strip_tags(ElementTree(root), PI) 421 self.assertEqual(_bytes('<!--comment1-->\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->'), 422 self._writeElement(root)) 423 424 root = XML(xml) 425 self.etree.strip_tags(ElementTree(root), Comment) 426 self.assertEqual(_bytes('<?PI1?>\n<test>TESTXT<?PI2?></test>\n<?PI1?>'), 427 self._writeElement(root)) 428 429 root = XML(xml) 430 self.etree.strip_tags(ElementTree(root), PI, Comment) 431 self.assertEqual(_bytes('<test>TESTXT</test>'), 432 self._writeElement(root)) 433 434 root = XML(xml) 435 self.etree.strip_tags(ElementTree(root), Comment, PI) 436 self.assertEqual(_bytes('<test>TESTXT</test>'), 437 self._writeElement(root))
438
439 - def test_strip_tags_doc_style(self):
440 XML = self.etree.XML 441 xml = _bytes(''' 442 <div> 443 <div> 444 I like <strong>sheep</strong>. 445 <br/> 446 I like lots of <strong>sheep</strong>. 447 <br/> 448 Click <a href="http://www.sheep.com">here</a> 449 for <a href="http://www.sheep.com">those</a> sheep. 450 <br/> 451 </div> 452 </div> 453 '''.strip()) 454 455 root = XML(xml) 456 self.etree.strip_tags(root, 'a') 457 self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''), xml).replace(_bytes('<br/>'), _bytes('<br></br>')), 458 self._writeElement(root)) 459 460 root = XML(xml) 461 self.etree.strip_tags(root, 'a', 'br') 462 self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''), 463 re.sub(_bytes('<br[^>]*>'), _bytes(''), xml)), 464 self._writeElement(root))
465
466 - def test_strip_tags_ns(self):
467 XML = self.etree.XML 468 xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>CT</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>') 469 470 root = XML(xml) 471 self.etree.strip_tags(root, 'a') 472 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>XA<b xmlns="urn:a"></b>BT<c xmlns="urn:x"></c>CTAT</x>XT</test>'), 473 self._writeElement(root)) 474 475 root = XML(xml) 476 self.etree.strip_tags(root, '{urn:a}b', 'c') 477 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 478 self._writeElement(root)) 479 480 root = XML(xml) 481 self.etree.strip_tags(root, '{urn:a}*', 'c') 482 self.assertEqual(_bytes('<test>TESTA<b>B<c xmlns="urn:c"></c>CT</b>BTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 483 self._writeElement(root))
484
485 - def test_strip_tags_and_remove(self):
486 # previously crashed 487 HTML = self.etree.HTML 488 root = HTML(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'))[0][0] 489 self.assertEqual(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'), 490 self.etree.tostring(root)) 491 self.etree.strip_tags(root, 'b') 492 self.assertEqual(_bytes('<div><h1>title</h1> foo <p>boo</p></div>'), 493 self.etree.tostring(root)) 494 root.remove(root[0]) 495 self.assertEqual(_bytes('<div><p>boo</p></div>'), 496 self.etree.tostring(root))
497
498 - def test_pi(self):
499 # lxml.etree separates target and text 500 Element = self.etree.Element 501 SubElement = self.etree.SubElement 502 ProcessingInstruction = self.etree.ProcessingInstruction 503 504 a = Element('a') 505 a.append(ProcessingInstruction('foo', 'some more text')) 506 self.assertEqual(a[0].target, 'foo') 507 self.assertEqual(a[0].text, 'some more text')
508
509 - def test_pi_parse(self):
510 XML = self.etree.XML 511 root = XML(_bytes("<test><?mypi my test ?></test>")) 512 self.assertEqual(root[0].target, "mypi") 513 self.assertEqual(root[0].text, "my test ")
514
516 XML = self.etree.XML 517 root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>")) 518 self.assertEqual(root[0].target, "mypi") 519 self.assertEqual(root[0].get('my'), "1") 520 self.assertEqual(root[0].get('test'), " abc ") 521 self.assertEqual(root[0].get('quotes'), "' '") 522 self.assertEqual(root[0].get('only'), None) 523 self.assertEqual(root[0].get('names'), None) 524 self.assertEqual(root[0].get('nope'), None)
525
527 XML = self.etree.XML 528 root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>")) 529 self.assertEqual(root[0].target, "mypi") 530 self.assertEqual(root[0].attrib['my'], "1") 531 self.assertEqual(root[0].attrib['test'], " abc ") 532 self.assertEqual(root[0].attrib['quotes'], "' '") 533 self.assertRaises(KeyError, root[0].attrib.__getitem__, 'only') 534 self.assertRaises(KeyError, root[0].attrib.__getitem__, 'names') 535 self.assertRaises(KeyError, root[0].attrib.__getitem__, 'nope')
536
537 - def test_deepcopy_pi(self):
538 # previously caused a crash 539 ProcessingInstruction = self.etree.ProcessingInstruction 540 541 a = ProcessingInstruction("PI", "ONE") 542 b = copy.deepcopy(a) 543 b.text = "ANOTHER" 544 545 self.assertEqual('ONE', a.text) 546 self.assertEqual('ANOTHER', b.text)
547
549 XML = self.etree.XML 550 tostring = self.etree.tostring 551 root = XML(_bytes("<?mypi my test ?><test/><!--comment -->")) 552 tree1 = self.etree.ElementTree(root) 553 self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"), 554 tostring(tree1)) 555 556 tree2 = copy.deepcopy(tree1) 557 self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"), 558 tostring(tree2)) 559 560 root2 = copy.deepcopy(tree1.getroot()) 561 self.assertEqual(_bytes("<test/>"), 562 tostring(root2))
563
565 XML = self.etree.XML 566 tostring = self.etree.tostring 567 xml = _bytes('<!DOCTYPE test [\n<!ENTITY entity "tasty">\n]>\n<test/>') 568 root = XML(xml) 569 tree1 = self.etree.ElementTree(root) 570 self.assertEqual(xml, tostring(tree1)) 571 572 tree2 = copy.deepcopy(tree1) 573 self.assertEqual(xml, tostring(tree2)) 574 575 root2 = copy.deepcopy(tree1.getroot()) 576 self.assertEqual(_bytes("<test/>"), 577 tostring(root2))
578
579 - def test_parse_remove_comments(self):
580 fromstring = self.etree.fromstring 581 tostring = self.etree.tostring 582 XMLParser = self.etree.XMLParser 583 584 xml = _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 585 parser = XMLParser(remove_comments=True) 586 root = fromstring(xml, parser) 587 self.assertEqual( 588 _bytes('<a><b><c/></b></a>'), 589 tostring(root))
590
591 - def test_parse_remove_pis(self):
592 parse = self.etree.parse 593 tostring = self.etree.tostring 594 XMLParser = self.etree.XMLParser 595 596 xml = _bytes('<?test?><a><?A?><b><?B?><c/></b><?C?></a><?tail?>') 597 598 f = BytesIO(xml) 599 tree = parse(f) 600 self.assertEqual( 601 xml, 602 tostring(tree)) 603 604 parser = XMLParser(remove_pis=True) 605 tree = parse(f, parser) 606 self.assertEqual( 607 _bytes('<a><b><c/></b></a>'), 608 tostring(tree))
609
611 # ET raises IOError only 612 parse = self.etree.parse 613 self.assertRaises(TypeError, parse, 'notthere.xml', object())
614
616 # ET removes comments 617 iterparse = self.etree.iterparse 618 tostring = self.etree.tostring 619 620 f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 621 events = list(iterparse(f)) 622 root = events[-1][1] 623 self.assertEqual(3, len(events)) 624 self.assertEqual( 625 _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'), 626 tostring(root))
627
628 - def test_iterparse_comments(self):
629 # ET removes comments 630 iterparse = self.etree.iterparse 631 tostring = self.etree.tostring 632 633 def name(event, el): 634 if event == 'comment': 635 return el.text 636 else: 637 return el.tag
638 639 f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 640 events = list(iterparse(f, events=('end', 'comment'))) 641 root = events[-1][1] 642 self.assertEqual(6, len(events)) 643 self.assertEqual(['A', ' B ', 'c', 'b', 'C', 'a'], 644 [ name(*item) for item in events ]) 645 self.assertEqual( 646 _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'), 647 tostring(root))
648
649 - def test_iterparse_pis(self):
650 # ET removes pis 651 iterparse = self.etree.iterparse 652 tostring = self.etree.tostring 653 ElementTree = self.etree.ElementTree 654 655 def name(event, el): 656 if event == 'pi': 657 return (el.target, el.text) 658 else: 659 return el.tag
660 661 f = BytesIO('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>') 662 events = list(iterparse(f, events=('end', 'pi'))) 663 root = events[-2][1] 664 self.assertEqual(8, len(events)) 665 self.assertEqual([('pia','a'), ('pib','b'), ('pic','c'), 'c', 'b', 666 ('pid','d'), 'a', ('pie','e')], 667 [ name(*item) for item in events ]) 668 self.assertEqual( 669 _bytes('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>'), 670 tostring(ElementTree(root))) 671
672 - def test_iterparse_remove_comments(self):
673 iterparse = self.etree.iterparse 674 tostring = self.etree.tostring 675 676 f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 677 events = list(iterparse(f, remove_comments=True, 678 events=('end', 'comment'))) 679 root = events[-1][1] 680 self.assertEqual(3, len(events)) 681 self.assertEqual(['c', 'b', 'a'], 682 [ el.tag for (event, el) in events ]) 683 self.assertEqual( 684 _bytes('<a><b><c/></b></a>'), 685 tostring(root))
686
687 - def test_iterparse_broken(self):
688 iterparse = self.etree.iterparse 689 f = BytesIO('<a><b><c/></a>') 690 # ET raises ExpatError, lxml raises XMLSyntaxError 691 self.assertRaises(self.etree.XMLSyntaxError, list, iterparse(f))
692
693 - def test_iterparse_broken_recover(self):
694 iterparse = self.etree.iterparse 695 f = BytesIO('<a><b><c/></a>') 696 it = iterparse(f, events=('start', 'end'), recover=True) 697 events = [(ev, el.tag) for ev, el in it] 698 root = it.root 699 self.assertTrue(root is not None) 700 701 self.assertEqual(1, events.count(('start', 'a'))) 702 self.assertEqual(1, events.count(('end', 'a'))) 703 704 self.assertEqual(1, events.count(('start', 'b'))) 705 self.assertEqual(1, events.count(('end', 'b'))) 706 707 self.assertEqual(1, events.count(('start', 'c'))) 708 self.assertEqual(1, events.count(('end', 'c')))
709
710 - def test_iterparse_broken_multi_recover(self):
711 iterparse = self.etree.iterparse 712 f = BytesIO('<a><b><c/></d><b><c/></a></b>') 713 it = iterparse(f, events=('start', 'end'), recover=True) 714 events = [(ev, el.tag) for ev, el in it] 715 root = it.root 716 self.assertTrue(root is not None) 717 718 self.assertEqual(1, events.count(('start', 'a'))) 719 self.assertEqual(1, events.count(('end', 'a'))) 720 721 self.assertEqual(2, events.count(('start', 'b'))) 722 self.assertEqual(2, events.count(('end', 'b'))) 723 724 self.assertEqual(2, events.count(('start', 'c'))) 725 self.assertEqual(2, events.count(('end', 'c')))
726
727 - def test_iterparse_strip(self):
728 iterparse = self.etree.iterparse 729 f = BytesIO(""" 730 <a> \n \n <b> b test </b> \n 731 732 \n\t <c> \n </c> </a> \n """) 733 iterator = iterparse(f, remove_blank_text=True) 734 text = [ (element.text, element.tail) 735 for event, element in iterator ] 736 self.assertEqual( 737 [(" b test ", None), (" \n ", None), (None, None)], 738 text)
739
740 - def test_iterparse_tag(self):
741 iterparse = self.etree.iterparse 742 f = BytesIO('<a><b><d/></b><c/></a>') 743 744 iterator = iterparse(f, tag="b", events=('start', 'end')) 745 events = list(iterator) 746 root = iterator.root 747 self.assertEqual( 748 [('start', root[0]), ('end', root[0])], 749 events)
750
751 - def test_iterparse_tag_all(self):
752 iterparse = self.etree.iterparse 753 f = BytesIO('<a><b><d/></b><c/></a>') 754 755 iterator = iterparse(f, tag="*", events=('start', 'end')) 756 events = list(iterator) 757 self.assertEqual( 758 8, 759 len(events))
760
761 - def test_iterparse_tag_ns(self):
762 iterparse = self.etree.iterparse 763 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 764 765 iterator = iterparse(f, tag="{urn:test:1}b", events=('start', 'end')) 766 events = list(iterator) 767 root = iterator.root 768 self.assertEqual( 769 [('start', root[0]), ('end', root[0])], 770 events)
771
772 - def test_iterparse_tag_ns_empty(self):
773 iterparse = self.etree.iterparse 774 f = BytesIO('<a><b><d/></b><c/></a>') 775 iterator = iterparse(f, tag="{}b", events=('start', 'end')) 776 events = list(iterator) 777 root = iterator.root 778 self.assertEqual( 779 [('start', root[0]), ('end', root[0])], 780 events) 781 782 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 783 iterator = iterparse(f, tag="{}b", events=('start', 'end')) 784 events = list(iterator) 785 root = iterator.root 786 self.assertEqual([], events)
787
788 - def test_iterparse_tag_ns_all(self):
789 iterparse = self.etree.iterparse 790 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 791 iterator = iterparse(f, tag="{urn:test:1}*", events=('start', 'end')) 792 events = list(iterator) 793 self.assertEqual(8, len(events))
794
795 - def test_iterparse_tag_ns_empty_all(self):
796 iterparse = self.etree.iterparse 797 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 798 iterator = iterparse(f, tag="{}*", events=('start', 'end')) 799 events = list(iterator) 800 self.assertEqual([], events) 801 802 f = BytesIO('<a><b><d/></b><c/></a>') 803 iterator = iterparse(f, tag="{}*", events=('start', 'end')) 804 events = list(iterator) 805 self.assertEqual(8, len(events))
806
807 - def test_iterparse_encoding_error(self):
808 text = _str('Søk på nettet') 809 wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>" 810 xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text) 811 ).encode('iso-8859-1') 812 813 self.assertRaises(self.etree.ParseError, 814 list, self.etree.iterparse(BytesIO(xml_latin1)))
815
816 - def test_iterparse_encoding_8bit_override(self):
817 text = _str('Søk på nettet', encoding="UTF-8") 818 wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>" 819 xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text) 820 ).encode('iso-8859-1') 821 822 iterator = self.etree.iterparse(BytesIO(xml_latin1), 823 encoding="iso-8859-1") 824 self.assertEqual(1, len(list(iterator))) 825 826 a = iterator.root 827 self.assertEqual(a.text, text)
828
829 - def test_iterparse_keep_cdata(self):
830 tostring = self.etree.tostring 831 f = BytesIO('<root><![CDATA[test]]></root>') 832 context = self.etree.iterparse(f, strip_cdata=False) 833 content = [ el.text for event,el in context ] 834 835 self.assertEqual(['test'], content) 836 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 837 tostring(context.root))
838
839 - def test_parser_encoding_unknown(self):
840 self.assertRaises( 841 LookupError, self.etree.XMLParser, encoding="hopefully unknown")
842
843 - def test_parser_encoding(self):
844 self.etree.XMLParser(encoding="ascii") 845 self.etree.XMLParser(encoding="utf-8") 846 self.etree.XMLParser(encoding="iso-8859-1")
847
848 - def test_feed_parser_recover(self):
849 parser = self.etree.XMLParser(recover=True) 850 851 parser.feed('<?xml version=') 852 parser.feed('"1.0"?><ro') 853 parser.feed('ot><') 854 parser.feed('a test="works"') 855 parser.feed('><othertag/></root') # <a> not closed! 856 parser.feed('>') 857 858 root = parser.close() 859 860 self.assertEqual(root.tag, "root") 861 self.assertEqual(len(root), 1) 862 self.assertEqual(root[0].tag, "a") 863 self.assertEqual(root[0].get("test"), "works") 864 self.assertEqual(len(root[0]), 1) 865 self.assertEqual(root[0][0].tag, "othertag")
866 # FIXME: would be nice to get some errors logged ... 867 #self.assertTrue(len(parser.error_log) > 0, "error log is empty") 868
869 - def test_feed_parser_recover_no_id_dict(self):
870 # test that recover mode plays nicely with the no-id-dict setup 871 parser = self.etree.XMLParser(recover=True, collect_ids=False) 872 873 parser.feed('<?xml version=') 874 parser.feed('"1.0"?><ro') 875 parser.feed('ot xml:id="123"><') 876 parser.feed('a test="works" xml:id=') 877 parser.feed('"321"><othertag/></root') # <a> not closed! 878 parser.feed('>') 879 880 root = parser.close() 881 882 self.assertEqual(root.tag, "root") 883 self.assertEqual(len(root), 1) 884 self.assertEqual(root[0].tag, "a") 885 self.assertEqual(root[0].get("test"), "works") 886 self.assertEqual(root[0].attrib, { 887 'test': 'works', 888 '{http://www.w3.org/XML/1998/namespace}id': '321'}) 889 self.assertEqual(len(root[0]), 1) 890 self.assertEqual(root[0][0].tag, "othertag")
891 # FIXME: would be nice to get some errors logged ... 892 #self.assertTrue(len(parser.error_log) > 0, "error log is empty") 893
894 - def test_elementtree_parser_target_type_error(self):
895 assertEqual = self.assertEqual 896 assertFalse = self.assertFalse 897 898 events = [] 899 class Target(object): 900 def start(self, tag, attrib): 901 events.append("start") 902 assertFalse(attrib) 903 assertEqual("TAG", tag)
904 def end(self, tag): 905 events.append("end") 906 assertEqual("TAG", tag) 907 def close(self): 908 return "DONE" # no Element! 909 910 parser = self.etree.XMLParser(target=Target()) 911 tree = self.etree.ElementTree() 912 913 self.assertRaises(TypeError, 914 tree.parse, BytesIO("<TAG/>"), parser=parser) 915 self.assertEqual(["start", "end"], events) 916
917 - def test_parser_target_feed_exception(self):
918 # ET doesn't call .close() on errors 919 events = [] 920 class Target(object): 921 def start(self, tag, attrib): 922 events.append("start-" + tag)
923 def end(self, tag): 924 events.append("end-" + tag) 925 if tag == 'a': 926 raise ValueError("dead and gone") 927 def data(self, data): 928 events.append("data-" + data) 929 def close(self): 930 events.append("close") 931 return "DONE" 932 933 parser = self.etree.XMLParser(target=Target()) 934 935 try: 936 parser.feed(_bytes('<root>A<a>ca</a>B</root>')) 937 done = parser.close() 938 self.fail("error expected, but parsing succeeded") 939 except ValueError: 940 done = 'value error received as expected' 941 942 self.assertEqual(["start-root", "data-A", "start-a", 943 "data-ca", "end-a", "close"], 944 events) 945
946 - def test_parser_target_fromstring_exception(self):
947 # ET doesn't call .close() on errors 948 events = [] 949 class Target(object): 950 def start(self, tag, attrib): 951 events.append("start-" + tag)
952 def end(self, tag): 953 events.append("end-" + tag) 954 if tag == 'a': 955 raise ValueError("dead and gone") 956 def data(self, data): 957 events.append("data-" + data) 958 def close(self): 959 events.append("close") 960 return "DONE" 961 962 parser = self.etree.XMLParser(target=Target()) 963 964 try: 965 done = self.etree.fromstring(_bytes('<root>A<a>ca</a>B</root>'), 966 parser=parser) 967 self.fail("error expected, but parsing succeeded") 968 except ValueError: 969 done = 'value error received as expected' 970 971 self.assertEqual(["start-root", "data-A", "start-a", 972 "data-ca", "end-a", "close"], 973 events) 974
975 - def test_parser_target_feed_no_id_dict(self):
976 # test that target parsing works nicely with the no-id-hash setup 977 events = [] 978 class Target(object): 979 def start(self, tag, attrib): 980 events.append("start-" + tag)
981 def end(self, tag): 982 events.append("end-" + tag) 983 def data(self, data): 984 events.append("data-" + data) 985 def comment(self, text): 986 events.append("comment-" + text) 987 def close(self): 988 return "DONE" 989 990 parser = self.etree.XMLParser(target=Target(), collect_ids=False) 991 992 parser.feed(_bytes('<!--a--><root xml:id="123">A<!--b-->')) 993 parser.feed(_bytes('<sub xml:id="321"/>B</root>')) 994 done = parser.close() 995 996 self.assertEqual("DONE", done) 997 self.assertEqual(["comment-a", "start-root", "data-A", "comment-b", 998 "start-sub", "end-sub", "data-B", "end-root"], 999 events) 1000
1001 - def test_parser_target_comment(self):
1002 events = [] 1003 class Target(object): 1004 def start(self, tag, attrib): 1005 events.append("start-" + tag)
1006 def end(self, tag): 1007 events.append("end-" + tag) 1008 def data(self, data): 1009 events.append("data-" + data) 1010 def comment(self, text): 1011 events.append("comment-" + text) 1012 def close(self): 1013 return "DONE" 1014 1015 parser = self.etree.XMLParser(target=Target()) 1016 1017 parser.feed(_bytes('<!--a--><root>A<!--b--><sub/><!--c-->B</root><!--d-->')) 1018 done = parser.close() 1019 1020 self.assertEqual("DONE", done) 1021 self.assertEqual(["comment-a", "start-root", "data-A", "comment-b", 1022 "start-sub", "end-sub", "comment-c", "data-B", 1023 "end-root", "comment-d"], 1024 events) 1025
1026 - def test_parser_target_pi(self):
1027 events = [] 1028 class Target(object): 1029 def start(self, tag, attrib): 1030 events.append("start-" + tag)
1031 def end(self, tag): 1032 events.append("end-" + tag) 1033 def data(self, data): 1034 events.append("data-" + data) 1035 def pi(self, target, data): 1036 events.append("pi-" + target + "-" + data) 1037 def close(self): 1038 return "DONE" 1039 1040 parser = self.etree.XMLParser(target=Target()) 1041 1042 parser.feed(_bytes('<?test a?><root>A<?test b?>B</root><?test c?>')) 1043 done = parser.close() 1044 1045 self.assertEqual("DONE", done) 1046 self.assertEqual(["pi-test-a", "start-root", "data-A", "pi-test-b", 1047 "data-B", "end-root", "pi-test-c"], 1048 events) 1049
1050 - def test_parser_target_cdata(self):
1051 events = [] 1052 class Target(object): 1053 def start(self, tag, attrib): 1054 events.append("start-" + tag)
1055 def end(self, tag): 1056 events.append("end-" + tag) 1057 def data(self, data): 1058 events.append("data-" + data) 1059 def close(self): 1060 return "DONE" 1061 1062 parser = self.etree.XMLParser(target=Target(), 1063 strip_cdata=False) 1064 1065 parser.feed(_bytes('<root>A<a><![CDATA[ca]]></a>B</root>')) 1066 done = parser.close() 1067 1068 self.assertEqual("DONE", done) 1069 self.assertEqual(["start-root", "data-A", "start-a", 1070 "data-ca", "end-a", "data-B", "end-root"], 1071 events) 1072
1073 - def test_parser_target_recover(self):
1074 events = [] 1075 class Target(object): 1076 def start(self, tag, attrib): 1077 events.append("start-" + tag)
1078 def end(self, tag): 1079 events.append("end-" + tag) 1080 def data(self, data): 1081 events.append("data-" + data) 1082 def close(self): 1083 events.append("close") 1084 return "DONE" 1085 1086 parser = self.etree.XMLParser(target=Target(), 1087 recover=True) 1088 1089 parser.feed(_bytes('<root>A<a>ca</a>B</not-root>')) 1090 done = parser.close() 1091 1092 self.assertEqual("DONE", done) 1093 self.assertEqual(["start-root", "data-A", "start-a", 1094 "data-ca", "end-a", "data-B", 1095 "end-root", "close"], 1096 events) 1097
1098 - def test_iterwalk_tag(self):
1099 iterwalk = self.etree.iterwalk 1100 root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>')) 1101 1102 iterator = iterwalk(root, tag="b", events=('start', 'end')) 1103 events = list(iterator) 1104 self.assertEqual( 1105 [('start', root[0]), ('end', root[0])], 1106 events)
1107
1108 - def test_iterwalk_tag_all(self):
1109 iterwalk = self.etree.iterwalk 1110 root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>')) 1111 1112 iterator = iterwalk(root, tag="*", events=('start', 'end')) 1113 events = list(iterator) 1114 self.assertEqual( 1115 8, 1116 len(events))
1117
1118 - def test_iterwalk(self):
1119 iterwalk = self.etree.iterwalk 1120 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1121 1122 events = list(iterwalk(root)) 1123 self.assertEqual( 1124 [('end', root[0]), ('end', root[1]), ('end', root)], 1125 events)
1126
1127 - def test_iterwalk_start(self):
1128 iterwalk = self.etree.iterwalk 1129 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1130 1131 iterator = iterwalk(root, events=('start',)) 1132 events = list(iterator) 1133 self.assertEqual( 1134 [('start', root), ('start', root[0]), ('start', root[1])], 1135 events)
1136
1137 - def test_iterwalk_start_end(self):
1138 iterwalk = self.etree.iterwalk 1139 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1140 1141 iterator = iterwalk(root, events=('start','end')) 1142 events = list(iterator) 1143 self.assertEqual( 1144 [('start', root), ('start', root[0]), ('end', root[0]), 1145 ('start', root[1]), ('end', root[1]), ('end', root)], 1146 events)
1147
1148 - def test_iterwalk_clear(self):
1149 iterwalk = self.etree.iterwalk 1150 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1151 1152 iterator = iterwalk(root) 1153 for event, elem in iterator: 1154 elem.clear() 1155 1156 self.assertEqual(0, 1157 len(root))
1158
1159 - def test_iterwalk_attrib_ns(self):
1160 iterwalk = self.etree.iterwalk 1161 root = self.etree.XML(_bytes('<a xmlns="ns1"><b><c xmlns="ns2"/></b></a>')) 1162 1163 attr_name = '{testns}bla' 1164 events = [] 1165 iterator = iterwalk(root, events=('start','end','start-ns','end-ns')) 1166 for event, elem in iterator: 1167 events.append(event) 1168 if event == 'start': 1169 if elem.tag != '{ns1}a': 1170 elem.set(attr_name, 'value') 1171 1172 self.assertEqual( 1173 ['start-ns', 'start', 'start', 'start-ns', 'start', 1174 'end', 'end-ns', 'end', 'end', 'end-ns'], 1175 events) 1176 1177 self.assertEqual( 1178 None, 1179 root.get(attr_name)) 1180 self.assertEqual( 1181 'value', 1182 root[0].get(attr_name))
1183
1184 - def test_iterwalk_getiterator(self):
1185 iterwalk = self.etree.iterwalk 1186 root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>')) 1187 1188 counts = [] 1189 for event, elem in iterwalk(root): 1190 counts.append(len(list(elem.getiterator()))) 1191 self.assertEqual( 1192 [1,2,1,4], 1193 counts)
1194
1195 - def test_resolve_string_dtd(self):
1196 parse = self.etree.parse 1197 parser = self.etree.XMLParser(dtd_validation=True) 1198 assertEqual = self.assertEqual 1199 test_url = _str("__nosuch.dtd") 1200 1201 class MyResolver(self.etree.Resolver): 1202 def resolve(self, url, id, context): 1203 assertEqual(url, test_url) 1204 return self.resolve_string( 1205 _str('''<!ENTITY myentity "%s"> 1206 <!ELEMENT doc ANY>''') % url, context)
1207 1208 parser.resolvers.add(MyResolver()) 1209 1210 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1211 tree = parse(StringIO(xml), parser) 1212 root = tree.getroot() 1213 self.assertEqual(root.text, test_url) 1214
1215 - def test_resolve_bytes_dtd(self):
1216 parse = self.etree.parse 1217 parser = self.etree.XMLParser(dtd_validation=True) 1218 assertEqual = self.assertEqual 1219 test_url = _str("__nosuch.dtd") 1220 1221 class MyResolver(self.etree.Resolver): 1222 def resolve(self, url, id, context): 1223 assertEqual(url, test_url) 1224 return self.resolve_string( 1225 (_str('''<!ENTITY myentity "%s"> 1226 <!ELEMENT doc ANY>''') % url).encode('utf-8'), 1227 context)
1228 1229 parser.resolvers.add(MyResolver()) 1230 1231 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1232 tree = parse(StringIO(xml), parser) 1233 root = tree.getroot() 1234 self.assertEqual(root.text, test_url) 1235
1236 - def test_resolve_filelike_dtd(self):
1237 parse = self.etree.parse 1238 parser = self.etree.XMLParser(dtd_validation=True) 1239 assertEqual = self.assertEqual 1240 test_url = _str("__nosuch.dtd") 1241 1242 class MyResolver(self.etree.Resolver): 1243 def resolve(self, url, id, context): 1244 assertEqual(url, test_url) 1245 return self.resolve_file( 1246 SillyFileLike( 1247 _str('''<!ENTITY myentity "%s"> 1248 <!ELEMENT doc ANY>''') % url), context)
1249 1250 parser.resolvers.add(MyResolver()) 1251 1252 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1253 tree = parse(StringIO(xml), parser) 1254 root = tree.getroot() 1255 self.assertEqual(root.text, test_url) 1256
1257 - def test_resolve_filename_dtd(self):
1258 parse = self.etree.parse 1259 parser = self.etree.XMLParser(attribute_defaults=True) 1260 assertEqual = self.assertEqual 1261 test_url = _str("__nosuch.dtd") 1262 1263 class MyResolver(self.etree.Resolver): 1264 def resolve(self, url, id, context): 1265 assertEqual(url, test_url) 1266 return self.resolve_filename( 1267 fileInTestDir('test.dtd'), context)
1268 1269 parser.resolvers.add(MyResolver()) 1270 1271 xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url 1272 tree = parse(StringIO(xml), parser) 1273 root = tree.getroot() 1274 self.assertEqual( 1275 root.attrib, {'default': 'valueA'}) 1276 self.assertEqual( 1277 root[0].attrib, {'default': 'valueB'}) 1278
1279 - def test_resolve_filename_dtd_relative(self):
1280 parse = self.etree.parse 1281 parser = self.etree.XMLParser(attribute_defaults=True) 1282 assertEqual = self.assertEqual 1283 test_url = _str("__nosuch.dtd") 1284 1285 class MyResolver(self.etree.Resolver): 1286 def resolve(self, url, id, context): 1287 expected = fileUrlInTestDir(test_url) 1288 url = url.replace('file://', 'file:') # depends on libxml2 version 1289 expected = expected.replace('file://', 'file:') 1290 assertEqual(url, expected) 1291 return self.resolve_filename( 1292 fileUrlInTestDir('test.dtd'), context)
1293 1294 parser.resolvers.add(MyResolver()) 1295 1296 xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url 1297 tree = parse(StringIO(xml), parser, 1298 base_url=fileUrlInTestDir('__test.xml')) 1299 root = tree.getroot() 1300 self.assertEqual( 1301 root.attrib, {'default': 'valueA'}) 1302 self.assertEqual( 1303 root[0].attrib, {'default': 'valueB'}) 1304
1305 - def test_resolve_file_dtd(self):
1306 parse = self.etree.parse 1307 parser = self.etree.XMLParser(attribute_defaults=True) 1308 assertEqual = self.assertEqual 1309 test_url = _str("__nosuch.dtd") 1310 1311 class MyResolver(self.etree.Resolver): 1312 def resolve(self, url, id, context): 1313 assertEqual(url, test_url) 1314 return self.resolve_file( 1315 open(fileInTestDir('test.dtd'), 'rb'), context)
1316 1317 parser.resolvers.add(MyResolver()) 1318 1319 xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url 1320 tree = parse(StringIO(xml), parser) 1321 root = tree.getroot() 1322 self.assertEqual( 1323 root.attrib, {'default': 'valueA'}) 1324 self.assertEqual( 1325 root[0].attrib, {'default': 'valueB'}) 1326
1327 - def test_resolve_empty(self):
1328 parse = self.etree.parse 1329 parser = self.etree.XMLParser(load_dtd=True) 1330 assertEqual = self.assertEqual 1331 test_url = _str("__nosuch.dtd") 1332 1333 class check(object): 1334 resolved = False
1335 1336 class MyResolver(self.etree.Resolver): 1337 def resolve(self, url, id, context): 1338 assertEqual(url, test_url) 1339 check.resolved = True 1340 return self.resolve_empty(context) 1341 1342 parser.resolvers.add(MyResolver()) 1343 1344 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1345 self.assertRaises(etree.XMLSyntaxError, parse, StringIO(xml), parser) 1346 self.assertTrue(check.resolved) 1347
1348 - def test_resolve_error(self):
1349 parse = self.etree.parse 1350 parser = self.etree.XMLParser(dtd_validation=True) 1351 1352 class _LocalException(Exception): 1353 pass
1354 1355 class MyResolver(self.etree.Resolver): 1356 def resolve(self, url, id, context): 1357 raise _LocalException 1358 1359 parser.resolvers.add(MyResolver()) 1360 1361 xml = '<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>' 1362 self.assertRaises(_LocalException, parse, BytesIO(xml), parser) 1363 1364 if etree.LIBXML_VERSION > (2,6,20):
1365 - def test_entity_parse(self):
1366 parse = self.etree.parse 1367 tostring = self.etree.tostring 1368 parser = self.etree.XMLParser(resolve_entities=False) 1369 Entity = self.etree.Entity 1370 1371 xml = _bytes('<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>') 1372 tree = parse(BytesIO(xml), parser) 1373 root = tree.getroot() 1374 self.assertEqual(root[0].tag, Entity) 1375 self.assertEqual(root[0].text, "&myentity;") 1376 self.assertEqual(root[0].tail, None) 1377 self.assertEqual(root[0].name, "myentity") 1378 1379 self.assertEqual(_bytes('<doc>&myentity;</doc>'), 1380 tostring(root))
1381
1382 - def test_entity_restructure(self):
1383 xml = _bytes('''<!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]> 1384 <root> 1385 <child1/> 1386 <child2/> 1387 <child3>&nbsp;</child3> 1388 </root>''') 1389 1390 parser = self.etree.XMLParser(resolve_entities=False) 1391 root = etree.fromstring(xml, parser) 1392 self.assertEqual([ el.tag for el in root ], 1393 ['child1', 'child2', 'child3']) 1394 1395 root[0] = root[-1] 1396 self.assertEqual([ el.tag for el in root ], 1397 ['child3', 'child2']) 1398 self.assertEqual(root[0][0].text, '&nbsp;') 1399 self.assertEqual(root[0][0].name, 'nbsp')
1400
1401 - def test_entity_append(self):
1402 Entity = self.etree.Entity 1403 Element = self.etree.Element 1404 tostring = self.etree.tostring 1405 1406 root = Element("root") 1407 root.append( Entity("test") ) 1408 1409 self.assertEqual(root[0].tag, Entity) 1410 self.assertEqual(root[0].text, "&test;") 1411 self.assertEqual(root[0].tail, None) 1412 self.assertEqual(root[0].name, "test") 1413 1414 self.assertEqual(_bytes('<root>&test;</root>'), 1415 tostring(root))
1416
1417 - def test_entity_values(self):
1418 Entity = self.etree.Entity 1419 self.assertEqual(Entity("test").text, '&test;') 1420 self.assertEqual(Entity("#17683").text, '&#17683;') 1421 self.assertEqual(Entity("#x1768").text, '&#x1768;') 1422 self.assertEqual(Entity("#x98AF").text, '&#x98AF;')
1423
1424 - def test_entity_error(self):
1425 Entity = self.etree.Entity 1426 self.assertRaises(ValueError, Entity, 'a b c') 1427 self.assertRaises(ValueError, Entity, 'a,b') 1428 self.assertRaises(ValueError, Entity, 'a\0b') 1429 self.assertRaises(ValueError, Entity, '#abc') 1430 self.assertRaises(ValueError, Entity, '#xxyz')
1431
1432 - def test_cdata(self):
1433 CDATA = self.etree.CDATA 1434 Element = self.etree.Element 1435 tostring = self.etree.tostring 1436 1437 root = Element("root") 1438 root.text = CDATA('test') 1439 1440 self.assertEqual('test', 1441 root.text) 1442 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 1443 tostring(root))
1444
1445 - def test_cdata_tail(self):
1446 CDATA = self.etree.CDATA 1447 Element = self.etree.Element 1448 SubElement = self.etree.SubElement 1449 tostring = self.etree.tostring 1450 1451 root = Element("root") 1452 child = SubElement(root, 'child') 1453 child.tail = CDATA('test') 1454 1455 self.assertEqual('test', child.tail) 1456 self.assertEqual(_bytes('<root><child/><![CDATA[test]]></root>'), 1457 tostring(root)) 1458 1459 root = Element("root") 1460 root.tail = CDATA('test') 1461 1462 self.assertEqual('test', root.tail) 1463 self.assertEqual(_bytes('<root/><![CDATA[test]]>'), 1464 tostring(root))
1465
1466 - def test_cdata_type(self):
1467 CDATA = self.etree.CDATA 1468 Element = self.etree.Element 1469 root = Element("root") 1470 1471 root.text = CDATA("test") 1472 self.assertEqual('test', root.text) 1473 1474 root.text = CDATA(_str("test")) 1475 self.assertEqual('test', root.text) 1476 1477 self.assertRaises(TypeError, CDATA, 1)
1478
1479 - def test_cdata_errors(self):
1480 CDATA = self.etree.CDATA 1481 Element = self.etree.Element 1482 1483 root = Element("root") 1484 cdata = CDATA('test') 1485 1486 self.assertRaises(TypeError, 1487 root.set, 'attr', cdata) 1488 self.assertRaises(TypeError, 1489 operator.setitem, root.attrib, 'attr', cdata)
1490
1491 - def test_cdata_parser(self):
1492 tostring = self.etree.tostring 1493 parser = self.etree.XMLParser(strip_cdata=False) 1494 root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser) 1495 1496 self.assertEqual('test', root.text) 1497 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 1498 tostring(root))
1499
1500 - def test_cdata_xpath(self):
1501 tostring = self.etree.tostring 1502 parser = self.etree.XMLParser(strip_cdata=False) 1503 root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser) 1504 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 1505 tostring(root)) 1506 1507 self.assertEqual(['test'], root.xpath('//text()'))
1508 1509 # TypeError in etree, AssertionError in ElementTree;
1510 - def test_setitem_assert(self):
1511 Element = self.etree.Element 1512 SubElement = self.etree.SubElement 1513 1514 a = Element('a') 1515 b = SubElement(a, 'b') 1516 1517 self.assertRaises(TypeError, 1518 a.__setitem__, 0, 'foo')
1519
1520 - def test_append_error(self):
1521 Element = self.etree.Element 1522 root = Element('root') 1523 # raises AssertionError in ElementTree 1524 self.assertRaises(TypeError, root.append, None) 1525 self.assertRaises(TypeError, root.extend, [None]) 1526 self.assertRaises(TypeError, root.extend, [Element('one'), None]) 1527 self.assertEqual('one', root[0].tag)
1528
1529 - def test_append_recursive_error(self):
1530 Element = self.etree.Element 1531 SubElement = self.etree.SubElement 1532 root = Element('root') 1533 self.assertRaises(ValueError, root.append, root) 1534 child = SubElement(root, 'child') 1535 self.assertRaises(ValueError, child.append, root) 1536 child2 = SubElement(child, 'child2') 1537 self.assertRaises(ValueError, child2.append, root) 1538 self.assertRaises(ValueError, child2.append, child) 1539 self.assertEqual('child2', root[0][0].tag)
1540
1541 - def test_addnext(self):
1542 Element = self.etree.Element 1543 SubElement = self.etree.SubElement 1544 root = Element('root') 1545 SubElement(root, 'a') 1546 SubElement(root, 'b') 1547 1548 self.assertEqual(['a', 'b'], 1549 [c.tag for c in root]) 1550 root[1].addnext(root[0]) 1551 self.assertEqual(['b', 'a'], 1552 [c.tag for c in root])
1553
1554 - def test_addprevious(self):
1555 Element = self.etree.Element 1556 SubElement = self.etree.SubElement 1557 root = Element('root') 1558 SubElement(root, 'a') 1559 SubElement(root, 'b') 1560 1561 self.assertEqual(['a', 'b'], 1562 [c.tag for c in root]) 1563 root[0].addprevious(root[1]) 1564 self.assertEqual(['b', 'a'], 1565 [c.tag for c in root])
1566
1567 - def test_addnext_cycle(self):
1568 Element = self.etree.Element 1569 SubElement = self.etree.SubElement 1570 root = Element('root') 1571 a = SubElement(root, 'a') 1572 b = SubElement(a, 'b') 1573 # appending parent as sibling is forbidden 1574 self.assertRaises(ValueError, b.addnext, a) 1575 self.assertEqual(['a'], [c.tag for c in root]) 1576 self.assertEqual(['b'], [c.tag for c in a])
1577
1578 - def test_addprevious_cycle(self):
1579 Element = self.etree.Element 1580 SubElement = self.etree.SubElement 1581 root = Element('root') 1582 a = SubElement(root, 'a') 1583 b = SubElement(a, 'b') 1584 # appending parent as sibling is forbidden 1585 self.assertRaises(ValueError, b.addprevious, a) 1586 self.assertEqual(['a'], [c.tag for c in root]) 1587 self.assertEqual(['b'], [c.tag for c in a])
1588
1589 - def test_addnext_cycle_long(self):
1590 Element = self.etree.Element 1591 SubElement = self.etree.SubElement 1592 root = Element('root') 1593 a = SubElement(root, 'a') 1594 b = SubElement(a, 'b') 1595 c = SubElement(b, 'c') 1596 # appending parent as sibling is forbidden 1597 self.assertRaises(ValueError, c.addnext, a)
1598
1599 - def test_addprevious_cycle_long(self):
1600 Element = self.etree.Element 1601 SubElement = self.etree.SubElement 1602 root = Element('root') 1603 a = SubElement(root, 'a') 1604 b = SubElement(a, 'b') 1605 c = SubElement(b, 'c') 1606 # appending parent as sibling is forbidden 1607 self.assertRaises(ValueError, c.addprevious, a)
1608
1609 - def test_addprevious_noops(self):
1610 Element = self.etree.Element 1611 SubElement = self.etree.SubElement 1612 root = Element('root') 1613 a = SubElement(root, 'a') 1614 b = SubElement(root, 'b') 1615 a.addprevious(a) 1616 self.assertEqual('a', root[0].tag) 1617 self.assertEqual('b', root[1].tag) 1618 b.addprevious(b) 1619 self.assertEqual('a', root[0].tag) 1620 self.assertEqual('b', root[1].tag) 1621 b.addprevious(a) 1622 self.assertEqual('a', root[0].tag) 1623 self.assertEqual('b', root[1].tag)
1624
1625 - def test_addnext_noops(self):
1626 Element = self.etree.Element 1627 SubElement = self.etree.SubElement 1628 root = Element('root') 1629 a = SubElement(root, 'a') 1630 b = SubElement(root, 'b') 1631 a.addnext(a) 1632 self.assertEqual('a', root[0].tag) 1633 self.assertEqual('b', root[1].tag) 1634 b.addnext(b) 1635 self.assertEqual('a', root[0].tag) 1636 self.assertEqual('b', root[1].tag) 1637 a.addnext(b) 1638 self.assertEqual('a', root[0].tag) 1639 self.assertEqual('b', root[1].tag)
1640
1641 - def test_addnext_root(self):
1642 Element = self.etree.Element 1643 a = Element('a') 1644 b = Element('b') 1645 self.assertRaises(TypeError, a.addnext, b)
1646
1647 - def test_addprevious_pi(self):
1648 Element = self.etree.Element 1649 SubElement = self.etree.SubElement 1650 PI = self.etree.PI 1651 root = Element('root') 1652 SubElement(root, 'a') 1653 pi = PI('TARGET', 'TEXT') 1654 pi.tail = "TAIL" 1655 1656 self.assertEqual(_bytes('<root><a></a></root>'), 1657 self._writeElement(root)) 1658 root[0].addprevious(pi) 1659 self.assertEqual(_bytes('<root><?TARGET TEXT?>TAIL<a></a></root>'), 1660 self._writeElement(root))
1661
1662 - def test_addprevious_root_pi(self):
1663 Element = self.etree.Element 1664 PI = self.etree.PI 1665 root = Element('root') 1666 pi = PI('TARGET', 'TEXT') 1667 pi.tail = "TAIL" 1668 1669 self.assertEqual(_bytes('<root></root>'), 1670 self._writeElement(root)) 1671 root.addprevious(pi) 1672 self.assertEqual(_bytes('<?TARGET TEXT?>\n<root></root>'), 1673 self._writeElement(root))
1674
1675 - def test_addnext_pi(self):
1676 Element = self.etree.Element 1677 SubElement = self.etree.SubElement 1678 PI = self.etree.PI 1679 root = Element('root') 1680 SubElement(root, 'a') 1681 pi = PI('TARGET', 'TEXT') 1682 pi.tail = "TAIL" 1683 1684 self.assertEqual(_bytes('<root><a></a></root>'), 1685 self._writeElement(root)) 1686 root[0].addnext(pi) 1687 self.assertEqual(_bytes('<root><a></a><?TARGET TEXT?>TAIL</root>'), 1688 self._writeElement(root))
1689
1690 - def test_addnext_root_pi(self):
1691 Element = self.etree.Element 1692 PI = self.etree.PI 1693 root = Element('root') 1694 pi = PI('TARGET', 'TEXT') 1695 pi.tail = "TAIL" 1696 1697 self.assertEqual(_bytes('<root></root>'), 1698 self._writeElement(root)) 1699 root.addnext(pi) 1700 self.assertEqual(_bytes('<root></root>\n<?TARGET TEXT?>'), 1701 self._writeElement(root))
1702
1703 - def test_addnext_comment(self):
1704 Element = self.etree.Element 1705 SubElement = self.etree.SubElement 1706 Comment = self.etree.Comment 1707 root = Element('root') 1708 SubElement(root, 'a') 1709 comment = Comment('TEXT ') 1710 comment.tail = "TAIL" 1711 1712 self.assertEqual(_bytes('<root><a></a></root>'), 1713 self._writeElement(root)) 1714 root[0].addnext(comment) 1715 self.assertEqual(_bytes('<root><a></a><!--TEXT -->TAIL</root>'), 1716 self._writeElement(root))
1717
1718 - def test_addnext_root_comment(self):
1719 Element = self.etree.Element 1720 Comment = self.etree.Comment 1721 root = Element('root') 1722 comment = Comment('TEXT ') 1723 comment.tail = "TAIL" 1724 1725 self.assertEqual(_bytes('<root></root>'), 1726 self._writeElement(root)) 1727 root.addnext(comment) 1728 self.assertEqual(_bytes('<root></root>\n<!--TEXT -->'), 1729 self._writeElement(root))
1730
1731 - def test_addprevious_comment(self):
1732 Element = self.etree.Element 1733 SubElement = self.etree.SubElement 1734 Comment = self.etree.Comment 1735 root = Element('root') 1736 SubElement(root, 'a') 1737 comment = Comment('TEXT ') 1738 comment.tail = "TAIL" 1739 1740 self.assertEqual(_bytes('<root><a></a></root>'), 1741 self._writeElement(root)) 1742 root[0].addprevious(comment) 1743 self.assertEqual(_bytes('<root><!--TEXT -->TAIL<a></a></root>'), 1744 self._writeElement(root))
1745
1746 - def test_addprevious_root_comment(self):
1747 Element = self.etree.Element 1748 Comment = self.etree.Comment 1749 root = Element('root') 1750 comment = Comment('TEXT ') 1751 comment.tail = "TAIL" 1752 1753 self.assertEqual(_bytes('<root></root>'), 1754 self._writeElement(root)) 1755 root.addprevious(comment) 1756 self.assertEqual(_bytes('<!--TEXT -->\n<root></root>'), 1757 self._writeElement(root))
1758 1759 # ET's Elements have items() and key(), but not values()
1760 - def test_attribute_values(self):
1761 XML = self.etree.XML 1762 1763 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 1764 values = root.values() 1765 values.sort() 1766 self.assertEqual(['Alpha', 'Beta', 'Gamma'], values)
1767 1768 # gives error in ElementTree
1769 - def test_comment_empty(self):
1770 Element = self.etree.Element 1771 Comment = self.etree.Comment 1772 1773 a = Element('a') 1774 a.append(Comment()) 1775 self.assertEqual( 1776 _bytes('<a><!----></a>'), 1777 self._writeElement(a))
1778 1779 # ElementTree ignores comments
1780 - def test_comment_parse_empty(self):
1781 ElementTree = self.etree.ElementTree 1782 tostring = self.etree.tostring 1783 1784 xml = _bytes('<a><b/><!----><c/></a>') 1785 f = BytesIO(xml) 1786 doc = ElementTree(file=f) 1787 a = doc.getroot() 1788 self.assertEqual( 1789 '', 1790 a[1].text) 1791 self.assertEqual( 1792 xml, 1793 tostring(a))
1794 1795 # ElementTree ignores comments
1796 - def test_comment_no_proxy_yet(self):
1797 ElementTree = self.etree.ElementTree 1798 1799 f = BytesIO('<a><b></b><!-- hoi --><c></c></a>') 1800 doc = ElementTree(file=f) 1801 a = doc.getroot() 1802 self.assertEqual( 1803 ' hoi ', 1804 a[1].text)
1805 1806 # does not raise an exception in ElementTree
1807 - def test_comment_immutable(self):
1808 Element = self.etree.Element 1809 Comment = self.etree.Comment 1810 1811 c = Comment() 1812 el = Element('myel') 1813 1814 self.assertRaises(TypeError, c.append, el) 1815 self.assertRaises(TypeError, c.insert, 0, el) 1816 self.assertRaises(TypeError, c.set, "myattr", "test")
1817
1818 - def test_comment_immutable_attrib(self):
1819 c = self.etree.Comment() 1820 self.assertEqual(0, len(c.attrib)) 1821 1822 self.assertFalse(c.attrib.__contains__('nope')) 1823 self.assertFalse('nope' in c.attrib) 1824 self.assertFalse('nope' in c.attrib.keys()) 1825 self.assertFalse('nope' in c.attrib.values()) 1826 self.assertFalse(('nope', 'huhu') in c.attrib.items()) 1827 1828 self.assertEqual([], list(c.attrib)) 1829 self.assertEqual([], list(c.attrib.keys())) 1830 self.assertEqual([], list(c.attrib.items())) 1831 self.assertEqual([], list(c.attrib.values())) 1832 self.assertEqual([], list(c.attrib.iterkeys())) 1833 self.assertEqual([], list(c.attrib.iteritems())) 1834 self.assertEqual([], list(c.attrib.itervalues())) 1835 1836 self.assertEqual('HUHU', c.attrib.pop('nope', 'HUHU')) 1837 self.assertRaises(KeyError, c.attrib.pop, 'nope') 1838 1839 self.assertRaises(KeyError, c.attrib.__getitem__, 'only') 1840 self.assertRaises(KeyError, c