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