1# -*- coding: utf-8 -*- 2 3""" 4Tests for the ElementTree API 5 6Only test cases that apply equally well to etree and ElementTree 7belong here. Note that there is a second test module called test_io.py 8for IO related test cases. 9""" 10 11from __future__ import absolute_import 12 13import copy 14import io 15import operator 16import os 17import re 18import sys 19import textwrap 20import unittest 21from contextlib import contextmanager 22from functools import wraps, partial 23from itertools import islice 24 25from .common_imports import ( 26 BytesIO, etree, HelperTestCase, 27 ElementTree, cElementTree, ET_VERSION, CET_VERSION, 28 filter_by_version, fileInTestDir, canonicalize, tmpfile, 29 _str, _bytes, unicode, IS_PYTHON2 30) 31 32if cElementTree is not None and (CET_VERSION <= (1,0,7) or sys.version_info[0] >= 3): 33 cElementTree = None 34 35if ElementTree is not None: 36 print("Comparing with ElementTree %s" % getattr(ElementTree, "VERSION", "?")) 37 38if cElementTree is not None: 39 print("Comparing with cElementTree %s" % getattr(cElementTree, "VERSION", "?")) 40 41 42def et_needs_pyversion(*version): 43 def wrap(method): 44 @wraps(method) 45 def testfunc(self, *args): 46 if self.etree is not etree and sys.version_info < version: 47 raise unittest.SkipTest("requires ET in Python %s" % '.'.join(map(str, version))) 48 return method(self, *args) 49 return testfunc 50 return wrap 51 52 53def et_exclude_pyversion(*version): 54 def wrap(method): 55 @wraps(method) 56 def testfunc(self, *args): 57 if self.etree is not etree and sys.version_info[:len(version)] == version: 58 raise unittest.SkipTest("requires ET in Python %s" % '.'.join(map(str, version))) 59 return method(self, *args) 60 return testfunc 61 return wrap 62 63 64class _ETreeTestCaseBase(HelperTestCase): 65 etree = None 66 required_versions_ET = {} 67 required_versions_cET = {} 68 69 def XMLParser(self, **kwargs): 70 try: 71 XMLParser = self.etree.XMLParser 72 except AttributeError: 73 assert 'ElementTree' in self.etree.__name__ 74 XMLParser = self.etree.TreeBuilder 75 return XMLParser(**kwargs) 76 77 try: 78 HelperTestCase.assertRegex 79 except AttributeError: 80 def assertRegex(self, *args, **kwargs): 81 return self.assertRegexpMatches(*args, **kwargs) 82 83 @et_needs_pyversion(3, 6) 84 def test_interface(self): 85 # Test element tree interface. 86 87 def check_string(string): 88 len(string) 89 for char in string: 90 self.assertEqual(len(char), 1, 91 msg="expected one-character string, got %r" % char) 92 new_string = string + "" 93 new_string = string + " " 94 string[:0] 95 96 def check_mapping(mapping): 97 len(mapping) 98 keys = mapping.keys() 99 items = mapping.items() 100 for key in keys: 101 item = mapping[key] 102 mapping["key"] = "value" 103 self.assertEqual(mapping["key"], "value", 104 msg="expected value string, got %r" % mapping["key"]) 105 106 def check_element(element): 107 self.assertTrue(self.etree.iselement(element), msg="not an element") 108 direlem = dir(element) 109 for attr in 'tag', 'attrib', 'text', 'tail': 110 self.assertTrue(hasattr(element, attr), 111 msg='no %s member' % attr) 112 self.assertIn(attr, direlem, 113 msg='no %s visible by dir' % attr) 114 115 check_string(element.tag) 116 check_mapping(element.attrib) 117 if element.text is not None: 118 check_string(element.text) 119 if element.tail is not None: 120 check_string(element.tail) 121 for elem in element: 122 check_element(elem) 123 124 element = self.etree.Element("tag") 125 check_element(element) 126 tree = self.etree.ElementTree(element) 127 check_element(tree.getroot()) 128 element = self.etree.Element(u"t\xe4g", key="value") 129 tree = self.etree.ElementTree(element) 130 # lxml and ET Py2: slightly different repr() 131 #self.assertRegex(repr(element), r"^<Element 't\xe4g' at 0x.*>$") 132 element = self.etree.Element("tag", key="value") 133 134 # Make sure all standard element methods exist. 135 136 def check_method(method): 137 self.assertTrue(hasattr(method, '__call__'), 138 msg="%s not callable" % method) 139 140 check_method(element.append) 141 check_method(element.extend) 142 check_method(element.insert) 143 check_method(element.remove) 144 # Removed in Py3.9 145 #check_method(element.getchildren) 146 check_method(element.find) 147 check_method(element.iterfind) 148 check_method(element.findall) 149 check_method(element.findtext) 150 check_method(element.clear) 151 check_method(element.get) 152 check_method(element.set) 153 check_method(element.keys) 154 check_method(element.items) 155 check_method(element.iter) 156 check_method(element.itertext) 157 # Removed in Py3.9 158 #check_method(element.getiterator) 159 160 # These methods return an iterable. See bug 6472. 161 162 def check_iter(it): 163 check_method(it.next if IS_PYTHON2 else it.__next__) 164 165 check_iter(element.iterfind("tag")) 166 check_iter(element.iterfind("*")) 167 check_iter(tree.iterfind("tag")) 168 check_iter(tree.iterfind("*")) 169 170 # These aliases are provided: 171 172 # not an alias in lxml 173 #self.assertEqual(self.etree.XML, self.etree.fromstring) 174 self.assertEqual(self.etree.PI, self.etree.ProcessingInstruction) 175 176 def test_element(self): 177 for i in range(10): 178 e = self.etree.Element('foo') 179 self.assertEqual(e.tag, 'foo') 180 self.assertEqual(e.text, None) 181 self.assertEqual(e.tail, None) 182 183 def test_simple(self): 184 Element = self.etree.Element 185 186 root = Element('root') 187 root.append(Element('one')) 188 root.append(Element('two')) 189 root.append(Element('three')) 190 self.assertEqual(3, len(root)) 191 self.assertEqual('one', root[0].tag) 192 self.assertEqual('two', root[1].tag) 193 self.assertEqual('three', root[2].tag) 194 self.assertRaises(IndexError, operator.getitem, root, 3) 195 196 # test weird dictionary interaction leading to segfault previously 197 def test_weird_dict_interaction(self): 198 root = self.etree.Element('root') 199 self.assertEqual(root.tag, "root") 200 add = self.etree.ElementTree(file=BytesIO('<foo>Foo</foo>')) 201 self.assertEqual(add.getroot().tag, "foo") 202 self.assertEqual(add.getroot().text, "Foo") 203 root.append(self.etree.Element('baz')) 204 self.assertEqual(root.tag, "root") 205 self.assertEqual(root[0].tag, "baz") 206 207 def test_subelement(self): 208 Element = self.etree.Element 209 SubElement = self.etree.SubElement 210 211 root = Element('root') 212 SubElement(root, 'one') 213 SubElement(root, 'two') 214 SubElement(root, 'three') 215 self.assertEqual(3, len(root)) 216 self.assertEqual('one', root[0].tag) 217 self.assertEqual('two', root[1].tag) 218 self.assertEqual('three', root[2].tag) 219 220 def test_element_contains(self): 221 Element = self.etree.Element 222 SubElement = self.etree.SubElement 223 224 root1 = Element('root') 225 SubElement(root1, 'one') 226 self.assertTrue(root1[0] in root1) 227 228 root2 = Element('root') 229 SubElement(root2, 'two') 230 SubElement(root2, 'three') 231 self.assertTrue(root2[0] in root2) 232 self.assertTrue(root2[1] in root2) 233 234 self.assertFalse(root1[0] in root2) 235 self.assertFalse(root2[0] in root1) 236 self.assertFalse(None in root2) 237 238 def test_element_indexing_with_text(self): 239 ElementTree = self.etree.ElementTree 240 241 f = BytesIO('<doc>Test<one>One</one></doc>') 242 doc = ElementTree(file=f) 243 root = doc.getroot() 244 self.assertEqual(1, len(root)) 245 self.assertEqual('one', root[0].tag) 246 self.assertRaises(IndexError, operator.getitem, root, 1) 247 248 def test_element_indexing_with_text2(self): 249 ElementTree = self.etree.ElementTree 250 251 f = BytesIO('<doc><one>One</one><two>Two</two>hm<three>Three</three></doc>') 252 doc = ElementTree(file=f) 253 root = doc.getroot() 254 self.assertEqual(3, len(root)) 255 self.assertEqual('one', root[0].tag) 256 self.assertEqual('two', root[1].tag) 257 self.assertEqual('three', root[2].tag) 258 259 def test_element_indexing_only_text(self): 260 ElementTree = self.etree.ElementTree 261 262 f = BytesIO('<doc>Test</doc>') 263 doc = ElementTree(file=f) 264 root = doc.getroot() 265 self.assertEqual(0, len(root)) 266 267 def test_element_indexing_negative(self): 268 Element = self.etree.Element 269 SubElement = self.etree.SubElement 270 a = Element('a') 271 b = SubElement(a, 'b') 272 c = SubElement(a, 'c') 273 d = SubElement(a, 'd') 274 self.assertEqual(d, a[-1]) 275 self.assertEqual(c, a[-2]) 276 self.assertEqual(b, a[-3]) 277 self.assertRaises(IndexError, operator.getitem, a, -4) 278 a[-1] = e = Element('e') 279 self.assertEqual(e, a[-1]) 280 del a[-1] 281 self.assertEqual(2, len(a)) 282 283 def test_elementtree(self): 284 ElementTree = self.etree.ElementTree 285 286 f = BytesIO('<doc><one>One</one><two>Two</two></doc>') 287 doc = ElementTree(file=f) 288 root = doc.getroot() 289 self.assertEqual(2, len(root)) 290 self.assertEqual('one', root[0].tag) 291 self.assertEqual('two', root[1].tag) 292 293 def test_text(self): 294 ElementTree = self.etree.ElementTree 295 296 f = BytesIO('<doc>This is a text</doc>') 297 doc = ElementTree(file=f) 298 root = doc.getroot() 299 self.assertEqual('This is a text', root.text) 300 301 def test_text_empty(self): 302 ElementTree = self.etree.ElementTree 303 304 f = BytesIO('<doc></doc>') 305 doc = ElementTree(file=f) 306 root = doc.getroot() 307 self.assertEqual(None, root.text) 308 309 def test_text_other(self): 310 ElementTree = self.etree.ElementTree 311 312 f = BytesIO('<doc><one>One</one></doc>') 313 doc = ElementTree(file=f) 314 root = doc.getroot() 315 self.assertEqual(None, root.text) 316 self.assertEqual('One', root[0].text) 317 318 def test_text_escape_in(self): 319 ElementTree = self.etree.ElementTree 320 321 f = BytesIO('<doc>This is > than a text</doc>') 322 doc = ElementTree(file=f) 323 root = doc.getroot() 324 self.assertEqual('This is > than a text', root.text) 325 326 def test_text_escape_out(self): 327 Element = self.etree.Element 328 329 a = Element("a") 330 a.text = "<>&" 331 self.assertXML(_bytes('<a><>&</a>'), 332 a) 333 334 def test_text_escape_tostring(self): 335 tostring = self.etree.tostring 336 Element = self.etree.Element 337 338 a = Element("a") 339 a.text = "<>&" 340 self.assertEqual(_bytes('<a><>&</a>'), 341 tostring(a)) 342 343 def test_text_str_subclass(self): 344 Element = self.etree.Element 345 346 class strTest(str): 347 pass 348 349 a = Element("a") 350 a.text = strTest("text") 351 self.assertXML(_bytes('<a>text</a>'), 352 a) 353 354 def test_tail(self): 355 ElementTree = self.etree.ElementTree 356 357 f = BytesIO('<doc>This is <i>mixed</i> content.</doc>') 358 doc = ElementTree(file=f) 359 root = doc.getroot() 360 self.assertEqual(1, len(root)) 361 self.assertEqual('This is ', root.text) 362 self.assertEqual(None, root.tail) 363 self.assertEqual('mixed', root[0].text) 364 self.assertEqual(' content.', root[0].tail) 365 366 def test_tail_str_subclass(self): 367 Element = self.etree.Element 368 SubElement = self.etree.SubElement 369 370 class strTest(str): 371 pass 372 373 a = Element("a") 374 SubElement(a, "t").tail = strTest("tail") 375 self.assertXML(_bytes('<a><t></t>tail</a>'), 376 a) 377 378 def _test_del_tail(self): 379 # this is discouraged for ET compat, should not be tested... 380 XML = self.etree.XML 381 382 root = XML(_bytes('<doc>This is <i>mixed</i> content.</doc>')) 383 self.assertEqual(1, len(root)) 384 self.assertEqual('This is ', root.text) 385 self.assertEqual(None, root.tail) 386 self.assertEqual('mixed', root[0].text) 387 self.assertEqual(' content.', root[0].tail) 388 389 del root[0].tail 390 391 self.assertEqual(1, len(root)) 392 self.assertEqual('This is ', root.text) 393 self.assertEqual(None, root.tail) 394 self.assertEqual('mixed', root[0].text) 395 self.assertEqual(None, root[0].tail) 396 397 root[0].tail = "TAIL" 398 399 self.assertEqual(1, len(root)) 400 self.assertEqual('This is ', root.text) 401 self.assertEqual(None, root.tail) 402 self.assertEqual('mixed', root[0].text) 403 self.assertEqual('TAIL', root[0].tail) 404 405 def test_ElementTree(self): 406 Element = self.etree.Element 407 ElementTree = self.etree.ElementTree 408 409 el = Element('hoi') 410 doc = ElementTree(el) 411 root = doc.getroot() 412 self.assertEqual(None, root.text) 413 self.assertEqual('hoi', root.tag) 414 415 def test_attrib(self): 416 ElementTree = self.etree.ElementTree 417 418 f = BytesIO('<doc one="One" two="Two"/>') 419 doc = ElementTree(file=f) 420 root = doc.getroot() 421 self.assertEqual('One', root.attrib['one']) 422 self.assertEqual('Two', root.attrib['two']) 423 self.assertRaises(KeyError, operator.getitem, root.attrib, 'three') 424 425 def test_attrib_get(self): 426 ElementTree = self.etree.ElementTree 427 428 f = BytesIO('<doc one="One" two="Two"/>') 429 doc = ElementTree(file=f) 430 root = doc.getroot() 431 self.assertEqual('One', root.attrib.get('one')) 432 self.assertEqual('Two', root.attrib.get('two')) 433 self.assertEqual(None, root.attrib.get('three')) 434 self.assertEqual('foo', root.attrib.get('three', 'foo')) 435 436 def test_attrib_dict(self): 437 ElementTree = self.etree.ElementTree 438 439 f = BytesIO('<doc one="One" two="Two"/>') 440 doc = ElementTree(file=f) 441 root = doc.getroot() 442 attrib = dict(root.attrib) 443 self.assertEqual('One', attrib['one']) 444 self.assertEqual('Two', attrib['two']) 445 self.assertRaises(KeyError, operator.getitem, attrib, 'three') 446 447 def test_attrib_copy(self): 448 ElementTree = self.etree.ElementTree 449 450 f = BytesIO('<doc one="One" two="Two"/>') 451 doc = ElementTree(file=f) 452 root = doc.getroot() 453 attrib = copy.copy(root.attrib) 454 self.assertEqual('One', attrib['one']) 455 self.assertEqual('Two', attrib['two']) 456 self.assertRaises(KeyError, operator.getitem, attrib, 'three') 457 458 def test_attrib_deepcopy(self): 459 ElementTree = self.etree.ElementTree 460 461 f = BytesIO('<doc one="One" two="Two"/>') 462 doc = ElementTree(file=f) 463 root = doc.getroot() 464 attrib = copy.deepcopy(root.attrib) 465 self.assertEqual('One', attrib['one']) 466 self.assertEqual('Two', attrib['two']) 467 self.assertRaises(KeyError, operator.getitem, attrib, 'three') 468 469 def test_attributes_get(self): 470 ElementTree = self.etree.ElementTree 471 472 f = BytesIO('<doc one="One" two="Two"/>') 473 doc = ElementTree(file=f) 474 root = doc.getroot() 475 self.assertEqual('One', root.get('one')) 476 self.assertEqual('Two', root.get('two')) 477 self.assertEqual(None, root.get('three')) 478 self.assertEqual('foo', root.get('three', 'foo')) 479 480 def test_attrib_clear(self): 481 XML = self.etree.XML 482 483 root = XML(_bytes('<doc one="One" two="Two"/>')) 484 self.assertEqual('One', root.get('one')) 485 self.assertEqual('Two', root.get('two')) 486 root.attrib.clear() 487 self.assertEqual(None, root.get('one')) 488 self.assertEqual(None, root.get('two')) 489 490 def test_attrib_set_clear(self): 491 Element = self.etree.Element 492 493 root = Element("root", one="One") 494 root.set("two", "Two") 495 self.assertEqual('One', root.get('one')) 496 self.assertEqual('Two', root.get('two')) 497 root.attrib.clear() 498 self.assertEqual(None, root.get('one')) 499 self.assertEqual(None, root.get('two')) 500 501 def test_attrib_ns_clear(self): 502 Element = self.etree.Element 503 SubElement = self.etree.SubElement 504 505 attribNS = '{http://foo/bar}x' 506 507 parent = Element('parent') 508 parent.set(attribNS, 'a') 509 child = SubElement(parent, 'child') 510 child.set(attribNS, 'b') 511 512 self.assertEqual('a', parent.get(attribNS)) 513 self.assertEqual('b', child.get(attribNS)) 514 515 parent.clear() 516 self.assertEqual(None, parent.get(attribNS)) 517 self.assertEqual('b', child.get(attribNS)) 518 519 def test_attrib_pop(self): 520 ElementTree = self.etree.ElementTree 521 522 f = BytesIO('<doc one="One" two="Two"/>') 523 doc = ElementTree(file=f) 524 root = doc.getroot() 525 self.assertEqual('One', root.attrib['one']) 526 self.assertEqual('Two', root.attrib['two']) 527 528 self.assertEqual('One', root.attrib.pop('one')) 529 530 self.assertEqual(None, root.attrib.get('one')) 531 self.assertEqual('Two', root.attrib['two']) 532 533 def test_attrib_pop_unknown(self): 534 root = self.etree.XML(_bytes('<doc one="One" two="Two"/>')) 535 self.assertRaises(KeyError, root.attrib.pop, 'NONE') 536 537 self.assertEqual('One', root.attrib['one']) 538 self.assertEqual('Two', root.attrib['two']) 539 540 def test_attrib_pop_default(self): 541 root = self.etree.XML(_bytes('<doc one="One" two="Two"/>')) 542 self.assertEqual('Three', root.attrib.pop('three', 'Three')) 543 544 def test_attrib_pop_empty_default(self): 545 root = self.etree.XML(_bytes('<doc/>')) 546 self.assertEqual('Three', root.attrib.pop('three', 'Three')) 547 548 def test_attrib_pop_invalid_args(self): 549 root = self.etree.XML(_bytes('<doc one="One" two="Two"/>')) 550 self.assertRaises(TypeError, root.attrib.pop, 'One', None, None) 551 552 def test_attribute_update_dict(self): 553 XML = self.etree.XML 554 555 root = XML(_bytes('<doc alpha="Alpha" beta="Beta"/>')) 556 items = list(root.attrib.items()) 557 items.sort() 558 self.assertEqual( 559 [('alpha', 'Alpha'), ('beta', 'Beta')], 560 items) 561 562 root.attrib.update({'alpha' : 'test', 'gamma' : 'Gamma'}) 563 564 items = list(root.attrib.items()) 565 items.sort() 566 self.assertEqual( 567 [('alpha', 'test'), ('beta', 'Beta'), ('gamma', 'Gamma')], 568 items) 569 570 def test_attribute_update_sequence(self): 571 XML = self.etree.XML 572 573 root = XML(_bytes('<doc alpha="Alpha" beta="Beta"/>')) 574 items = list(root.attrib.items()) 575 items.sort() 576 self.assertEqual( 577 [('alpha', 'Alpha'), ('beta', 'Beta')], 578 items) 579 580 root.attrib.update({'alpha' : 'test', 'gamma' : 'Gamma'}.items()) 581 582 items = list(root.attrib.items()) 583 items.sort() 584 self.assertEqual( 585 [('alpha', 'test'), ('beta', 'Beta'), ('gamma', 'Gamma')], 586 items) 587 588 def test_attribute_update_iter(self): 589 XML = self.etree.XML 590 591 root = XML(_bytes('<doc alpha="Alpha" beta="Beta"/>')) 592 items = list(root.attrib.items()) 593 items.sort() 594 self.assertEqual( 595 [('alpha', 'Alpha'), ('beta', 'Beta')], 596 items) 597 598 root.attrib.update(iter({'alpha' : 'test', 'gamma' : 'Gamma'}.items())) 599 600 items = list(root.attrib.items()) 601 items.sort() 602 self.assertEqual( 603 [('alpha', 'test'), ('beta', 'Beta'), ('gamma', 'Gamma')], 604 items) 605 606 def test_attribute_update_attrib(self): 607 XML = self.etree.XML 608 609 root = XML(_bytes('<doc alpha="Alpha" beta="Beta"/>')) 610 items = list(root.attrib.items()) 611 items.sort() 612 self.assertEqual( 613 [('alpha', 'Alpha'), ('beta', 'Beta')], 614 items) 615 616 other = XML(_bytes('<doc alpha="test" gamma="Gamma"/>')) 617 root.attrib.update(other.attrib) 618 619 items = list(root.attrib.items()) 620 items.sort() 621 self.assertEqual( 622 [('alpha', 'test'), ('beta', 'Beta'), ('gamma', 'Gamma')], 623 items) 624 625 def test_attribute_keys(self): 626 XML = self.etree.XML 627 628 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 629 keys = list(root.attrib.keys()) 630 keys.sort() 631 self.assertEqual(['alpha', 'beta', 'gamma'], keys) 632 633 def test_attribute_keys2(self): 634 XML = self.etree.XML 635 636 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 637 keys = list(root.keys()) 638 keys.sort() 639 self.assertEqual(['alpha', 'beta', 'gamma'], keys) 640 641 def test_attribute_items2(self): 642 XML = self.etree.XML 643 644 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 645 items = list(root.items()) 646 items.sort() 647 self.assertEqual( 648 [('alpha','Alpha'), ('beta','Beta'), ('gamma','Gamma')], 649 items) 650 651 def test_attribute_keys_ns(self): 652 XML = self.etree.XML 653 654 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 655 keys = list(root.keys()) 656 keys.sort() 657 self.assertEqual(['bar', '{http://ns.codespeak.net/test}baz'], 658 keys) 659 660 def test_attribute_values(self): 661 XML = self.etree.XML 662 663 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 664 values = list(root.attrib.values()) 665 values.sort() 666 self.assertEqual(['Alpha', 'Beta', 'Gamma'], values) 667 668 def test_attribute_values_ns(self): 669 XML = self.etree.XML 670 671 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 672 values = list(root.attrib.values()) 673 values.sort() 674 self.assertEqual( 675 ['Bar', 'Baz'], values) 676 677 def test_attribute_items(self): 678 XML = self.etree.XML 679 680 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 681 items = list(root.attrib.items()) 682 items.sort() 683 self.assertEqual([ 684 ('alpha', 'Alpha'), 685 ('beta', 'Beta'), 686 ('gamma', 'Gamma'), 687 ], 688 items) 689 690 def test_attribute_items_ns(self): 691 XML = self.etree.XML 692 693 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 694 items = list(root.attrib.items()) 695 items.sort() 696 self.assertEqual( 697 [('bar', 'Bar'), ('{http://ns.codespeak.net/test}baz', 'Baz')], 698 items) 699 700 def test_attribute_str(self): 701 XML = self.etree.XML 702 703 expected = "{'{http://ns.codespeak.net/test}baz': 'Baz', 'bar': 'Bar'}" 704 alternative = "{'bar': 'Bar', '{http://ns.codespeak.net/test}baz': 'Baz'}" 705 706 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 707 try: 708 self.assertEqual(expected, str(root.attrib)) 709 except AssertionError: 710 self.assertEqual(alternative, str(root.attrib)) 711 712 def test_attribute_contains(self): 713 XML = self.etree.XML 714 715 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 716 self.assertEqual( 717 True, 'bar' in root.attrib) 718 self.assertEqual( 719 False, 'baz' in root.attrib) 720 self.assertEqual( 721 False, 'hah' in root.attrib) 722 self.assertEqual( 723 True, 724 '{http://ns.codespeak.net/test}baz' in root.attrib) 725 726 def test_attribute_set(self): 727 Element = self.etree.Element 728 729 root = Element("root") 730 root.set("attr", "TEST") 731 self.assertEqual("TEST", root.get("attr")) 732 733 def test_attrib_as_attrib(self): 734 Element = self.etree.Element 735 736 root = Element("root") 737 root.set("attr", "TEST") 738 self.assertEqual("TEST", root.attrib["attr"]) 739 740 root2 = Element("root2", root.attrib) 741 self.assertEqual("TEST", root2.attrib["attr"]) 742 743 def test_attribute_iterator(self): 744 XML = self.etree.XML 745 746 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma" />')) 747 result = [] 748 for key in root.attrib: 749 result.append(key) 750 result.sort() 751 self.assertEqual(['alpha', 'beta', 'gamma'], result) 752 753 def test_attribute_manipulation(self): 754 Element = self.etree.Element 755 756 a = Element('a') 757 a.attrib['foo'] = 'Foo' 758 a.attrib['bar'] = 'Bar' 759 self.assertEqual('Foo', a.attrib['foo']) 760 del a.attrib['foo'] 761 self.assertRaises(KeyError, operator.getitem, a.attrib, 'foo') 762 763 def test_del_attribute_ns(self): 764 Element = self.etree.Element 765 766 a = Element('a') 767 a.attrib['{http://a/}foo'] = 'Foo' 768 a.attrib['{http://a/}bar'] = 'Bar' 769 self.assertEqual(None, a.get('foo')) 770 self.assertEqual('Foo', a.get('{http://a/}foo')) 771 self.assertEqual('Foo', a.attrib['{http://a/}foo']) 772 773 self.assertRaises(KeyError, operator.delitem, a.attrib, 'foo') 774 self.assertEqual('Foo', a.attrib['{http://a/}foo']) 775 776 del a.attrib['{http://a/}foo'] 777 self.assertRaises(KeyError, operator.getitem, a.attrib, 'foo') 778 779 def test_del_attribute_ns_parsed(self): 780 XML = self.etree.XML 781 782 a = XML(_bytes('<a xmlns:nsa="http://a/" nsa:foo="FooNS" foo="Foo" />')) 783 784 self.assertEqual('Foo', a.attrib['foo']) 785 self.assertEqual('FooNS', a.attrib['{http://a/}foo']) 786 787 del a.attrib['foo'] 788 self.assertEqual('FooNS', a.attrib['{http://a/}foo']) 789 self.assertRaises(KeyError, operator.getitem, a.attrib, 'foo') 790 self.assertRaises(KeyError, operator.delitem, a.attrib, 'foo') 791 792 del a.attrib['{http://a/}foo'] 793 self.assertRaises(KeyError, operator.getitem, a.attrib, '{http://a/}foo') 794 self.assertRaises(KeyError, operator.getitem, a.attrib, 'foo') 795 796 a = XML(_bytes('<a xmlns:nsa="http://a/" foo="Foo" nsa:foo="FooNS" />')) 797 798 self.assertEqual('Foo', a.attrib['foo']) 799 self.assertEqual('FooNS', a.attrib['{http://a/}foo']) 800 801 del a.attrib['foo'] 802 self.assertEqual('FooNS', a.attrib['{http://a/}foo']) 803 self.assertRaises(KeyError, operator.getitem, a.attrib, 'foo') 804 805 del a.attrib['{http://a/}foo'] 806 self.assertRaises(KeyError, operator.getitem, a.attrib, '{http://a/}foo') 807 self.assertRaises(KeyError, operator.getitem, a.attrib, 'foo') 808 809 def test_XML(self): 810 XML = self.etree.XML 811 812 root = XML(_bytes('<doc>This is a text.</doc>')) 813 self.assertEqual(0, len(root)) 814 self.assertEqual('This is a text.', root.text) 815 816 def test_XMLID(self): 817 XMLID = self.etree.XMLID 818 XML = self.etree.XML 819 xml_text = _bytes(''' 820 <document> 821 <h1 id="chapter1">...</h1> 822 <p id="note1" class="note">...</p> 823 <p>Regular paragraph.</p> 824 <p xml:id="xmlid">XML:ID paragraph.</p> 825 <p id="warn1" class="warning">...</p> 826 </document> 827 ''') 828 829 root, dic = XMLID(xml_text) 830 root2 = XML(xml_text) 831 self.assertEqual(self._writeElement(root), 832 self._writeElement(root2)) 833 expected = { 834 "chapter1" : root[0], 835 "note1" : root[1], 836 "warn1" : root[4] 837 } 838 self.assertEqual(dic, expected) 839 840 def test_fromstring(self): 841 fromstring = self.etree.fromstring 842 843 root = fromstring('<doc>This is a text.</doc>') 844 self.assertEqual(0, len(root)) 845 self.assertEqual('This is a text.', root.text) 846 847 required_versions_ET['test_fromstringlist'] = (1,3) 848 def test_fromstringlist(self): 849 fromstringlist = self.etree.fromstringlist 850 851 root = fromstringlist(["<do", "c>T", "hi", "s is", 852 " a text.<", "/doc", ">"]) 853 self.assertEqual(0, len(root)) 854 self.assertEqual('This is a text.', root.text) 855 856 required_versions_ET['test_fromstringlist_characters'] = (1,3) 857 def test_fromstringlist_characters(self): 858 fromstringlist = self.etree.fromstringlist 859 860 root = fromstringlist(list('<doc>This is a text.</doc>')) 861 self.assertEqual(0, len(root)) 862 self.assertEqual('This is a text.', root.text) 863 864 required_versions_ET['test_fromstringlist_single'] = (1,3) 865 def test_fromstringlist_single(self): 866 fromstringlist = self.etree.fromstringlist 867 868 root = fromstringlist(['<doc>This is a text.</doc>']) 869 self.assertEqual(0, len(root)) 870 self.assertEqual('This is a text.', root.text) 871 872 def test_iselement(self): 873 iselement = self.etree.iselement 874 Element = self.etree.Element 875 ElementTree = self.etree.ElementTree 876 XML = self.etree.XML 877 Comment = self.etree.Comment 878 ProcessingInstruction = self.etree.ProcessingInstruction 879 880 el = Element('hoi') 881 self.assertTrue(iselement(el)) 882 883 el2 = XML(_bytes('<foo/>')) 884 self.assertTrue(iselement(el2)) 885 886 tree = ElementTree(element=Element('dag')) 887 self.assertTrue(not iselement(tree)) 888 self.assertTrue(iselement(tree.getroot())) 889 890 c = Comment('test') 891 self.assertTrue(iselement(c)) 892 893 p = ProcessingInstruction("test", "some text") 894 self.assertTrue(iselement(p)) 895 896 def test_iteration(self): 897 XML = self.etree.XML 898 899 root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>')) 900 result = [] 901 for el in root: 902 result.append(el.tag) 903 self.assertEqual(['one', 'two', 'three'], result) 904 905 def test_iteration_empty(self): 906 XML = self.etree.XML 907 908 root = XML(_bytes('<doc></doc>')) 909 result = [] 910 for el in root: 911 result.append(el.tag) 912 self.assertEqual([], result) 913 914 def test_iteration_text_only(self): 915 XML = self.etree.XML 916 917 root = XML(_bytes('<doc>Text</doc>')) 918 result = [] 919 for el in root: 920 result.append(el.tag) 921 self.assertEqual([], result) 922 923 def test_iteration_set_tail_empty(self): 924 # this would cause a crash in the past 925 fromstring = self.etree.fromstring 926 root = fromstring('<html><p></p>x</html>') 927 for elem in root: 928 elem.tail = '' 929 930 def test_iteration_clear_tail(self): 931 # this would cause a crash in the past 932 fromstring = self.etree.fromstring 933 root = fromstring('<html><p></p>x</html>') 934 for elem in root: 935 elem.tail = None 936 937 def test_iteration_reversed(self): 938 XML = self.etree.XML 939 root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>')) 940 result = [] 941 for el in reversed(root): 942 result.append(el.tag) 943 self.assertEqual(['three', 'two', 'one'], result) 944 945 def test_iteration_subelement(self): 946 XML = self.etree.XML 947 948 root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>')) 949 result = [] 950 add = True 951 for el in root: 952 result.append(el.tag) 953 if add: 954 self.etree.SubElement(root, 'four') 955 add = False 956 self.assertEqual(['one', 'two', 'three', 'four'], result) 957 958 def test_iteration_del_child(self): 959 XML = self.etree.XML 960 961 root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>')) 962 result = [] 963 for el in root: 964 result.append(el.tag) 965 del root[-1] 966 self.assertEqual(['one', 'two'], result) 967 968 def test_iteration_double(self): 969 XML = self.etree.XML 970 971 root = XML(_bytes('<doc><one/><two/></doc>')) 972 result = [] 973 for el0 in root: 974 result.append(el0.tag) 975 for el1 in root: 976 result.append(el1.tag) 977 self.assertEqual(['one','one', 'two', 'two', 'one', 'two'], result) 978 979 required_versions_ET['test_itertext'] = (1,3) 980 def test_itertext(self): 981 # ET 1.3+ 982 XML = self.etree.XML 983 root = XML(_bytes("<root>RTEXT<a></a>ATAIL<b/><c>CTEXT</c>CTAIL</root>")) 984 985 text = list(root.itertext()) 986 self.assertEqual(["RTEXT", "ATAIL", "CTEXT", "CTAIL"], 987 text) 988 989 required_versions_ET['test_itertext_child'] = (1,3) 990 def test_itertext_child(self): 991 # ET 1.3+ 992 XML = self.etree.XML 993 root = XML(_bytes("<root>RTEXT<a></a>ATAIL<b/><c>CTEXT</c>CTAIL</root>")) 994 995 text = list(root[2].itertext()) 996 self.assertEqual(["CTEXT"], 997 text) 998 999 def test_findall(self): 1000 XML = self.etree.XML 1001 root = XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')) 1002 self.assertEqual(len(list(root.findall("c"))), 1) 1003 self.assertEqual(len(list(root.findall(".//c"))), 2) 1004 self.assertEqual(len(list(root.findall(".//b"))), 3) 1005 self.assertEqual(len(list(root.findall(".//b"))[0]), 1) 1006 self.assertEqual(len(list(root.findall(".//b"))[1]), 0) 1007 self.assertEqual(len(list(root.findall(".//b"))[2]), 0) 1008 1009 def test_findall_ns(self): 1010 XML = self.etree.XML 1011 root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>')) 1012 self.assertEqual(len(list(root.findall(".//{X}b"))), 2) 1013 self.assertEqual(len(list(root.findall(".//b"))), 3) 1014 self.assertEqual(len(list(root.findall("b"))), 2) 1015 1016 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 1017 def test_findall_wildcard(self): 1018 def summarize_list(l): 1019 return [el.tag for el in l] 1020 1021 root = self.etree.XML(''' 1022 <a xmlns:x="X" xmlns:y="Y"> 1023 <x:b><c/></x:b> 1024 <b/> 1025 <c><x:b/><b/></c><y:b/> 1026 </a>''') 1027 root.append(self.etree.Comment('test')) 1028 1029 self.assertEqual(summarize_list(root.findall("{*}b")), 1030 ['{X}b', 'b', '{Y}b']) 1031 self.assertEqual(summarize_list(root.findall("{*}c")), 1032 ['c']) 1033 self.assertEqual(summarize_list(root.findall("{X}*")), 1034 ['{X}b']) 1035 self.assertEqual(summarize_list(root.findall("{Y}*")), 1036 ['{Y}b']) 1037 self.assertEqual(summarize_list(root.findall("{}*")), 1038 ['b', 'c']) 1039 self.assertEqual(summarize_list(root.findall("{}b")), # only for consistency 1040 ['b']) 1041 self.assertEqual(summarize_list(root.findall("{}b")), 1042 summarize_list(root.findall("b"))) 1043 self.assertEqual(summarize_list(root.findall("{*}*")), 1044 ['{X}b', 'b', 'c', '{Y}b']) 1045 self.assertEqual(summarize_list(root.findall("{*}*") 1046 + ([] if self.etree is etree else [root[-1]])), 1047 summarize_list(root.findall("*"))) 1048 1049 self.assertEqual(summarize_list(root.findall(".//{*}b")), 1050 ['{X}b', 'b', '{X}b', 'b', '{Y}b']) 1051 self.assertEqual(summarize_list(root.findall(".//{*}c")), 1052 ['c', 'c']) 1053 self.assertEqual(summarize_list(root.findall(".//{X}*")), 1054 ['{X}b', '{X}b']) 1055 self.assertEqual(summarize_list(root.findall(".//{Y}*")), 1056 ['{Y}b']) 1057 self.assertEqual(summarize_list(root.findall(".//{}*")), 1058 ['c', 'b', 'c', 'b']) 1059 self.assertEqual(summarize_list(root.findall(".//{}b")), 1060 ['b', 'b']) 1061 1062 def test_element_with_attributes_keywords(self): 1063 Element = self.etree.Element 1064 1065 el = Element('tag', foo='Foo', bar='Bar') 1066 self.assertEqual('Foo', el.attrib['foo']) 1067 self.assertEqual('Bar', el.attrib['bar']) 1068 1069 def test_element_with_attributes(self): 1070 Element = self.etree.Element 1071 1072 el = Element('tag', {'foo': 'Foo', 'bar': 'Bar'}) 1073 self.assertEqual('Foo', el.attrib['foo']) 1074 self.assertEqual('Bar', el.attrib['bar']) 1075 1076 def test_element_with_attributes_extra(self): 1077 Element = self.etree.Element 1078 1079 el = Element('tag', {'foo': 'Foo', 'bar': 'Bar'}, baz='Baz') 1080 self.assertEqual('Foo', el.attrib['foo']) 1081 self.assertEqual('Bar', el.attrib['bar']) 1082 self.assertEqual('Baz', el.attrib['baz']) 1083 1084 def test_element_with_attributes_extra_duplicate(self): 1085 Element = self.etree.Element 1086 1087 el = Element('tag', {'foo': 'Foo', 'bar': 'Bar'}, bar='Baz') 1088 self.assertEqual('Foo', el.attrib['foo']) 1089 self.assertEqual('Baz', el.attrib['bar']) 1090 1091 def test_element_with_attributes_ns(self): 1092 Element = self.etree.Element 1093 1094 el = Element('tag', {'{ns1}foo':'Foo', '{ns2}bar':'Bar'}) 1095 self.assertEqual('Foo', el.attrib['{ns1}foo']) 1096 self.assertEqual('Bar', el.attrib['{ns2}bar']) 1097 1098 def test_subelement_with_attributes(self): 1099 Element = self.etree.Element 1100 SubElement = self.etree.SubElement 1101 1102 el = Element('tag') 1103 SubElement(el, 'foo', {'foo':'Foo'}, baz="Baz") 1104 self.assertEqual("Baz", el[0].attrib['baz']) 1105 self.assertEqual('Foo', el[0].attrib['foo']) 1106 1107 def test_subelement_with_attributes_ns(self): 1108 Element = self.etree.Element 1109 SubElement = self.etree.SubElement 1110 1111 el = Element('tag') 1112 SubElement(el, 'foo', {'{ns1}foo':'Foo', '{ns2}bar':'Bar'}) 1113 self.assertEqual('Foo', el[0].attrib['{ns1}foo']) 1114 self.assertEqual('Bar', el[0].attrib['{ns2}bar']) 1115 1116 def test_write(self): 1117 ElementTree = self.etree.ElementTree 1118 XML = self.etree.XML 1119 1120 for i in range(10): 1121 f = BytesIO() 1122 root = XML(_bytes('<doc%s>This is a test.</doc%s>' % (i, i))) 1123 tree = ElementTree(element=root) 1124 tree.write(f) 1125 data = f.getvalue() 1126 self.assertEqual( 1127 _bytes('<doc%s>This is a test.</doc%s>' % (i, i)), 1128 canonicalize(data)) 1129 1130 required_versions_ET['test_write_method_html'] = (1,3) 1131 def test_write_method_html(self): 1132 ElementTree = self.etree.ElementTree 1133 Element = self.etree.Element 1134 SubElement = self.etree.SubElement 1135 1136 html = Element('html') 1137 body = SubElement(html, 'body') 1138 p = SubElement(body, 'p') 1139 p.text = "html" 1140 SubElement(p, 'br').tail = "test" 1141 1142 tree = ElementTree(element=html) 1143 f = BytesIO() 1144 tree.write(f, method="html") 1145 data = f.getvalue().replace(_bytes('\n'),_bytes('')) 1146 1147 self.assertEqual(_bytes('<html><body><p>html<br>test</p></body></html>'), 1148 data) 1149 1150 required_versions_ET['test_write_method_text'] = (1,3) 1151 def test_write_method_text(self): 1152 ElementTree = self.etree.ElementTree 1153 Element = self.etree.Element 1154 SubElement = self.etree.SubElement 1155 1156 a = Element('a') 1157 a.text = "A" 1158 a.tail = "tail" 1159 b = SubElement(a, 'b') 1160 b.text = "B" 1161 b.tail = "TAIL" 1162 c = SubElement(a, 'c') 1163 c.text = "C" 1164 1165 tree = ElementTree(element=a) 1166 f = BytesIO() 1167 tree.write(f, method="text") 1168 data = f.getvalue() 1169 1170 self.assertEqual(_bytes('ABTAILCtail'), 1171 data) 1172 1173 def test_write_fail(self): 1174 ElementTree = self.etree.ElementTree 1175 XML = self.etree.XML 1176 1177 tree = ElementTree( XML(_bytes('<doc>This is a test.</doc>')) ) 1178 self.assertRaises(IOError, tree.write, 1179 "definitely////\\-\\nonexisting\\-\\////FILE") 1180 1181 # this could trigger a crash, apparently because the document 1182 # reference was prematurely garbage collected 1183 def test_crash(self): 1184 Element = self.etree.Element 1185 1186 element = Element('tag') 1187 for i in range(10): 1188 element.attrib['key'] = 'value' 1189 value = element.attrib['key'] 1190 self.assertEqual(value, 'value') 1191 1192 # from doctest; for some reason this caused crashes too 1193 def test_write_ElementTreeDoctest(self): 1194 Element = self.etree.Element 1195 ElementTree = self.etree.ElementTree 1196 1197 f = BytesIO() 1198 for i in range(10): 1199 element = Element('tag%s' % i) 1200 self._check_element(element) 1201 tree = ElementTree(element) 1202 tree.write(f) 1203 self._check_element_tree(tree) 1204 1205 def test_subelement_reference(self): 1206 Element = self.etree.Element 1207 SubElement = self.etree.SubElement 1208 1209 el = Element('foo') 1210 el2 = SubElement(el, 'bar') 1211 el3 = SubElement(el2, 'baz') 1212 1213 al = Element('foo2') 1214 al2 = SubElement(al, 'bar2') 1215 al3 = SubElement(al2, 'baz2') 1216 1217 # now move al2 into el 1218 el.append(al2) 1219 1220 # now change al3 directly 1221 al3.text = 'baz2-modified' 1222 1223 # it should have changed through this route too 1224 self.assertEqual( 1225 'baz2-modified', 1226 el[1][0].text) 1227 1228 def test_set_text(self): 1229 Element = self.etree.Element 1230 SubElement = self.etree.SubElement 1231 1232 a = Element('a') 1233 b = SubElement(a, 'b') 1234 a.text = 'hoi' 1235 self.assertEqual( 1236 'hoi', 1237 a.text) 1238 self.assertEqual( 1239 'b', 1240 a[0].tag) 1241 1242 def test_set_text2(self): 1243 Element = self.etree.Element 1244 SubElement = self.etree.SubElement 1245 1246 a = Element('a') 1247 a.text = 'hoi' 1248 b = SubElement(a ,'b') 1249 self.assertEqual( 1250 'hoi', 1251 a.text) 1252 self.assertEqual( 1253 'b', 1254 a[0].tag) 1255 1256 def test_set_text_none(self): 1257 Element = self.etree.Element 1258 1259 a = Element('a') 1260 1261 a.text = 'foo' 1262 a.text = None 1263 1264 self.assertEqual( 1265 None, 1266 a.text) 1267 self.assertXML(_bytes('<a></a>'), a) 1268 1269 def test_set_text_empty(self): 1270 Element = self.etree.Element 1271 1272 a = Element('a') 1273 self.assertEqual(None, a.text) 1274 1275 a.text = '' 1276 self.assertEqual('', a.text) 1277 self.assertXML(_bytes('<a></a>'), a) 1278 1279 def test_tail1(self): 1280 Element = self.etree.Element 1281 SubElement = self.etree.SubElement 1282 1283 a = Element('a') 1284 a.tail = 'dag' 1285 self.assertEqual('dag', 1286 a.tail) 1287 b = SubElement(a, 'b') 1288 b.tail = 'hoi' 1289 self.assertEqual('hoi', 1290 b.tail) 1291 self.assertEqual('dag', 1292 a.tail) 1293 1294 def test_tail_append(self): 1295 Element = self.etree.Element 1296 1297 a = Element('a') 1298 b = Element('b') 1299 b.tail = 'b_tail' 1300 a.append(b) 1301 self.assertEqual('b_tail', 1302 b.tail) 1303 1304 def test_tail_set_twice(self): 1305 Element = self.etree.Element 1306 SubElement = self.etree.SubElement 1307 1308 a = Element('a') 1309 b = SubElement(a, 'b') 1310 b.tail = 'foo' 1311 b.tail = 'bar' 1312 self.assertEqual('bar', 1313 b.tail) 1314 self.assertXML(_bytes('<a><b></b>bar</a>'), a) 1315 1316 def test_tail_set_none(self): 1317 Element = self.etree.Element 1318 a = Element('a') 1319 a.tail = 'foo' 1320 a.tail = None 1321 self.assertEqual( 1322 None, 1323 a.tail) 1324 self.assertXML(_bytes('<a></a>'), a) 1325 1326 required_versions_ET['test_extend'] = (1,3) 1327 def test_extend(self): 1328 root = self.etree.Element('foo') 1329 for i in range(3): 1330 element = self.etree.SubElement(root, 'a%s' % i) 1331 element.text = "text%d" % i 1332 element.tail = "tail%d" % i 1333 1334 elements = [] 1335 for i in range(3): 1336 new_element = self.etree.Element("test%s" % i) 1337 new_element.text = "TEXT%s" % i 1338 new_element.tail = "TAIL%s" % i 1339 elements.append(new_element) 1340 1341 root.extend(elements) 1342 1343 self.assertEqual( 1344 ["a0", "a1", "a2", "test0", "test1", "test2"], 1345 [ el.tag for el in root ]) 1346 self.assertEqual( 1347 ["text0", "text1", "text2", "TEXT0", "TEXT1", "TEXT2"], 1348 [ el.text for el in root ]) 1349 self.assertEqual( 1350 ["tail0", "tail1", "tail2", "TAIL0", "TAIL1", "TAIL2"], 1351 [ el.tail for el in root ]) 1352 1353 def test_comment(self): 1354 Element = self.etree.Element 1355 SubElement = self.etree.SubElement 1356 Comment = self.etree.Comment 1357 1358 a = Element('a') 1359 a.append(Comment('foo')) 1360 self.assertEqual(a[0].tag, Comment) 1361 self.assertEqual(a[0].text, 'foo') 1362 1363 # ElementTree < 1.3 adds whitespace around comments 1364 required_versions_ET['test_comment_text'] = (1,3) 1365 def test_comment_text(self): 1366 Element = self.etree.Element 1367 SubElement = self.etree.SubElement 1368 Comment = self.etree.Comment 1369 tostring = self.etree.tostring 1370 1371 a = Element('a') 1372 a.append(Comment('foo')) 1373 self.assertEqual(a[0].text, 'foo') 1374 1375 self.assertEqual( 1376 _bytes('<a><!--foo--></a>'), 1377 tostring(a)) 1378 1379 a[0].text = "TEST" 1380 self.assertEqual(a[0].text, 'TEST') 1381 1382 self.assertEqual( 1383 _bytes('<a><!--TEST--></a>'), 1384 tostring(a)) 1385 1386 # ElementTree < 1.3 adds whitespace around comments 1387 required_versions_ET['test_comment_whitespace'] = (1,3) 1388 def test_comment_whitespace(self): 1389 Element = self.etree.Element 1390 SubElement = self.etree.SubElement 1391 Comment = self.etree.Comment 1392 tostring = self.etree.tostring 1393 1394 a = Element('a') 1395 a.append(Comment(' foo ')) 1396 self.assertEqual(a[0].text, ' foo ') 1397 self.assertEqual( 1398 _bytes('<a><!-- foo --></a>'), 1399 tostring(a)) 1400 1401 def test_comment_nonsense(self): 1402 Comment = self.etree.Comment 1403 c = Comment('foo') 1404 self.assertEqual({}, c.attrib) 1405 self.assertEqual([], list(c.keys())) 1406 self.assertEqual([], list(c.items())) 1407 self.assertEqual(None, c.get('hoi')) 1408 self.assertEqual(0, len(c)) 1409 # should not iterate 1410 for i in c: 1411 pass 1412 1413 def test_pi(self): 1414 # lxml.etree separates target and text 1415 Element = self.etree.Element 1416 SubElement = self.etree.SubElement 1417 ProcessingInstruction = self.etree.ProcessingInstruction 1418 1419 a = Element('a') 1420 a.append(ProcessingInstruction('foo', 'some more text')) 1421 self.assertEqual(a[0].tag, ProcessingInstruction) 1422 self.assertXML(_bytes("<a><?foo some more text?></a>"), 1423 a) 1424 1425 def test_processinginstruction(self): 1426 # lxml.etree separates target and text 1427 Element = self.etree.Element 1428 SubElement = self.etree.SubElement 1429 ProcessingInstruction = self.etree.PI 1430 1431 a = Element('a') 1432 a.append(ProcessingInstruction('foo', 'some more text')) 1433 self.assertEqual(a[0].tag, ProcessingInstruction) 1434 self.assertXML(_bytes("<a><?foo some more text?></a>"), 1435 a) 1436 1437 def test_pi_nonsense(self): 1438 ProcessingInstruction = self.etree.ProcessingInstruction 1439 pi = ProcessingInstruction('foo') 1440 self.assertEqual({}, pi.attrib) 1441 self.assertEqual([], list(pi.keys())) 1442 self.assertEqual([], list(pi.items())) 1443 self.assertEqual(None, pi.get('hoi')) 1444 self.assertEqual(0, len(pi)) 1445 # should not iterate 1446 for i in pi: 1447 pass 1448 1449 def test_setitem(self): 1450 Element = self.etree.Element 1451 SubElement = self.etree.SubElement 1452 1453 a = Element('a') 1454 b = SubElement(a, 'b') 1455 c = Element('c') 1456 a[0] = c 1457 self.assertEqual( 1458 c, 1459 a[0]) 1460 self.assertXML(_bytes('<a><c></c></a>'), 1461 a) 1462 self.assertXML(_bytes('<b></b>'), 1463 b) 1464 1465 def test_setitem2(self): 1466 Element = self.etree.Element 1467 SubElement = self.etree.SubElement 1468 1469 a = Element('a') 1470 for i in range(5): 1471 b = SubElement(a, 'b%s' % i) 1472 c = SubElement(b, 'c') 1473 for i in range(5): 1474 d = Element('d') 1475 e = SubElement(d, 'e') 1476 a[i] = d 1477 self.assertXML( 1478 _bytes('<a><d><e></e></d><d><e></e></d><d><e></e></d><d><e></e></d><d><e></e></d></a>'), 1479 a) 1480 self.assertXML(_bytes('<c></c>'), 1481 c) 1482 1483 def test_setitem_replace(self): 1484 Element = self.etree.Element 1485 SubElement = self.etree.SubElement 1486 1487 a = Element('a') 1488 SubElement(a, 'b') 1489 d = Element('d') 1490 a[0] = d 1491 self.assertXML(_bytes('<a><d></d></a>'), a) 1492 1493 def test_setitem_indexerror(self): 1494 Element = self.etree.Element 1495 SubElement = self.etree.SubElement 1496 1497 a = Element('a') 1498 b = SubElement(a, 'b') 1499 1500 self.assertRaises(IndexError, operator.setitem, a, 1, Element('c')) 1501 1502 def test_setitem_tail(self): 1503 Element = self.etree.Element 1504 SubElement = self.etree.SubElement 1505 1506 a = Element('a') 1507 b = SubElement(a, 'b') 1508 b.tail = 'B2' 1509 c = Element('c') 1510 c.tail = 'C2' 1511 1512 a[0] = c 1513 self.assertXML( 1514 _bytes('<a><c></c>C2</a>'), 1515 a) 1516 1517 def test_tag_write(self): 1518 Element = self.etree.Element 1519 SubElement = self.etree.SubElement 1520 1521 a = Element('a') 1522 b = SubElement(a, 'b') 1523 1524 a.tag = 'c' 1525 1526 self.assertEqual( 1527 'c', 1528 a.tag) 1529 1530 self.assertXML( 1531 _bytes('<c><b></b></c>'), 1532 a) 1533 1534 def test_tag_reset_ns(self): 1535 Element = self.etree.Element 1536 SubElement = self.etree.SubElement 1537 tostring = self.etree.tostring 1538 1539 a = Element('{a}a') 1540 b1 = SubElement(a, '{a}b') 1541 b2 = SubElement(a, '{b}b') 1542 1543 self.assertEqual('{a}b', b1.tag) 1544 1545 b1.tag = 'c' 1546 1547 # can't use C14N here! 1548 self.assertEqual('c', b1.tag) 1549 self.assertEqual(_bytes('<c'), tostring(b1)[:2]) 1550 self.assertTrue(_bytes('<c') in tostring(a)) 1551 1552 def test_tag_reset_root_ns(self): 1553 Element = self.etree.Element 1554 SubElement = self.etree.SubElement 1555 tostring = self.etree.tostring 1556 1557 a = Element('{a}a') 1558 b1 = SubElement(a, '{a}b') 1559 b2 = SubElement(a, '{b}b') 1560 1561 a.tag = 'c' 1562 1563 self.assertEqual( 1564 'c', 1565 a.tag) 1566 1567 # can't use C14N here! 1568 self.assertEqual('c', a.tag) 1569 self.assertEqual(_bytes('<c'), tostring(a)[:2]) 1570 1571 def test_tag_str_subclass(self): 1572 Element = self.etree.Element 1573 1574 class strTest(str): 1575 pass 1576 1577 a = Element("a") 1578 a.tag = strTest("TAG") 1579 self.assertXML(_bytes('<TAG></TAG>'), 1580 a) 1581 1582 def test_delitem(self): 1583 Element = self.etree.Element 1584 SubElement = self.etree.SubElement 1585 1586 a = Element('a') 1587 b = SubElement(a, 'b') 1588 c = SubElement(a, 'c') 1589 d = SubElement(a, 'd') 1590 1591 del a[1] 1592 self.assertXML( 1593 _bytes('<a><b></b><d></d></a>'), 1594 a) 1595 1596 del a[0] 1597 self.assertXML( 1598 _bytes('<a><d></d></a>'), 1599 a) 1600 1601 del a[0] 1602 self.assertXML( 1603 _bytes('<a></a>'), 1604 a) 1605 # move deleted element into other tree afterwards 1606 other = Element('other') 1607 other.append(c) 1608 self.assertXML( 1609 _bytes('<other><c></c></other>'), 1610 other) 1611 1612 def test_del_insert(self): 1613 Element = self.etree.Element 1614 SubElement = self.etree.SubElement 1615 1616 a = Element('a') 1617 b = SubElement(a, 'b') 1618 bs = SubElement(b, 'bs') 1619 c = SubElement(a, 'c') 1620 cs = SubElement(c, 'cs') 1621 1622 el = a[0] 1623 self.assertXML( 1624 _bytes('<a><b><bs></bs></b><c><cs></cs></c></a>'), 1625 a) 1626 self.assertXML(_bytes('<b><bs></bs></b>'), b) 1627 self.assertXML(_bytes('<c><cs></cs></c>'), c) 1628 1629 del a[0] 1630 self.assertXML( 1631 _bytes('<a><c><cs></cs></c></a>'), 1632 a) 1633 self.assertXML(_bytes('<b><bs></bs></b>'), b) 1634 self.assertXML(_bytes('<c><cs></cs></c>'), c) 1635 1636 a.insert(0, el) 1637 self.assertXML( 1638 _bytes('<a><b><bs></bs></b><c><cs></cs></c></a>'), 1639 a) 1640 self.assertXML(_bytes('<b><bs></bs></b>'), b) 1641 self.assertXML(_bytes('<c><cs></cs></c>'), c) 1642 1643 def test_del_setitem(self): 1644 Element = self.etree.Element 1645 SubElement = self.etree.SubElement 1646 1647 a = Element('a') 1648 b = SubElement(a, 'b') 1649 bs = SubElement(b, 'bs') 1650 c = SubElement(a, 'c') 1651 cs = SubElement(c, 'cs') 1652 1653 el = a[0] 1654 del a[0] 1655 a[0] = el 1656 self.assertXML( 1657 _bytes('<a><b><bs></bs></b></a>'), 1658 a) 1659 self.assertXML(_bytes('<b><bs></bs></b>'), b) 1660 self.assertXML(_bytes('<c><cs></cs></c>'), c) 1661 1662 def test_del_setslice(self): 1663 Element = self.etree.Element 1664 SubElement = self.etree.SubElement 1665 1666 a = Element('a') 1667 b = SubElement(a, 'b') 1668 bs = SubElement(b, 'bs') 1669 c = SubElement(a, 'c') 1670 cs = SubElement(c, 'cs') 1671 1672 el = a[0] 1673 del a[0] 1674 a[0:0] = [el] 1675 self.assertXML( 1676 _bytes('<a><b><bs></bs></b><c><cs></cs></c></a>'), 1677 a) 1678 self.assertXML(_bytes('<b><bs></bs></b>'), b) 1679 self.assertXML(_bytes('<c><cs></cs></c>'), c) 1680 1681 def test_replace_slice_tail(self): 1682 XML = self.etree.XML 1683 a = XML(_bytes('<a><b></b>B2<c></c>C2</a>')) 1684 b, c = a 1685 1686 a[:] = [] 1687 1688 self.assertEqual("B2", b.tail) 1689 self.assertEqual("C2", c.tail) 1690 1691 def test_merge_namespaced_subtree_as_slice(self): 1692 XML = self.etree.XML 1693 root = XML(_bytes( 1694 '<foo><bar xmlns:baz="http://huhu"><puh><baz:bump1 /><baz:bump2 /></puh></bar></foo>')) 1695 root[:] = root.findall('.//puh') # delete bar from hierarchy 1696 1697 # previously, this lost a namespace declaration on bump2 1698 result = self.etree.tostring(root) 1699 foo = self.etree.fromstring(result) 1700 1701 self.assertEqual('puh', foo[0].tag) 1702 self.assertEqual('{http://huhu}bump1', foo[0][0].tag) 1703 self.assertEqual('{http://huhu}bump2', foo[0][1].tag) 1704 1705 def test_delitem_tail_dealloc(self): 1706 ElementTree = self.etree.ElementTree 1707 f = BytesIO('<a><b></b>B2<c></c>C2</a>') 1708 doc = ElementTree(file=f) 1709 a = doc.getroot() 1710 del a[0] 1711 self.assertXML( 1712 _bytes('<a><c></c>C2</a>'), 1713 a) 1714 1715 def test_delitem_tail(self): 1716 ElementTree = self.etree.ElementTree 1717 f = BytesIO('<a><b></b>B2<c></c>C2</a>') 1718 doc = ElementTree(file=f) 1719 a = doc.getroot() 1720 b, c = a 1721 del a[0] 1722 self.assertXML( 1723 _bytes('<a><c></c>C2</a>'), 1724 a) 1725 self.assertEqual("B2", b.tail) 1726 self.assertEqual("C2", c.tail) 1727 1728 def test_clear(self): 1729 Element = self.etree.Element 1730 1731 a = Element('a') 1732 a.text = 'foo' 1733 a.tail = 'bar' 1734 a.set('hoi', 'dag') 1735 a.clear() 1736 self.assertEqual(None, a.text) 1737 self.assertEqual(None, a.tail) 1738 self.assertEqual(None, a.get('hoi')) 1739 self.assertEqual('a', a.tag) 1740 1741 def test_clear_sub(self): 1742 Element = self.etree.Element 1743 SubElement = self.etree.SubElement 1744 1745 a = Element('a') 1746 a.text = 'foo' 1747 a.tail = 'bar' 1748 a.set('hoi', 'dag') 1749 b = SubElement(a, 'b') 1750 c = SubElement(b, 'c') 1751 a.clear() 1752 self.assertEqual(None, a.text) 1753 self.assertEqual(None, a.tail) 1754 self.assertEqual(None, a.get('hoi')) 1755 self.assertEqual('a', a.tag) 1756 self.assertEqual(0, len(a)) 1757 self.assertXML(_bytes('<a></a>'), 1758 a) 1759 self.assertXML(_bytes('<b><c></c></b>'), 1760 b) 1761 1762 def test_clear_tail(self): 1763 ElementTree = self.etree.ElementTree 1764 f = BytesIO('<a><b></b>B2<c></c>C2</a>') 1765 doc = ElementTree(file=f) 1766 a = doc.getroot() 1767 a.clear() 1768 self.assertXML( 1769 _bytes('<a></a>'), 1770 a) 1771 1772 def test_insert(self): 1773 Element = self.etree.Element 1774 SubElement = self.etree.SubElement 1775 1776 a = Element('a') 1777 b = SubElement(a, 'b') 1778 c = SubElement(a, 'c') 1779 d = Element('d') 1780 a.insert(0, d) 1781 1782 self.assertEqual( 1783 d, 1784 a[0]) 1785 1786 self.assertXML( 1787 _bytes('<a><d></d><b></b><c></c></a>'), 1788 a) 1789 1790 e = Element('e') 1791 a.insert(2, e) 1792 self.assertEqual( 1793 e, 1794 a[2]) 1795 self.assertXML( 1796 _bytes('<a><d></d><b></b><e></e><c></c></a>'), 1797 a) 1798 1799 def test_insert_name_interning(self): 1800 # See GH#268 / LP#1773749. 1801 Element = self.etree.Element 1802 SubElement = self.etree.SubElement 1803 1804 # Use unique names to make sure they are new in the tag name dict. 1805 import uuid 1806 names = dict((k, 'tag-' + str(uuid.uuid4())) for k in 'abcde') 1807 1808 a = Element(names['a']) 1809 b = SubElement(a, names['b']) 1810 c = SubElement(a, names['c']) 1811 d = Element(names['d']) 1812 a.insert(0, d) 1813 1814 self.assertEqual( 1815 d, 1816 a[0]) 1817 1818 self.assertXML( 1819 _bytes('<%(a)s><%(d)s></%(d)s><%(b)s></%(b)s><%(c)s></%(c)s></%(a)s>' % names), 1820 a) 1821 1822 e = Element(names['e']) 1823 a.insert(2, e) 1824 self.assertEqual( 1825 e, 1826 a[2]) 1827 self.assertXML( 1828 _bytes('<%(a)s><%(d)s></%(d)s><%(b)s></%(b)s><%(e)s></%(e)s><%(c)s></%(c)s></%(a)s>' % names), 1829 a) 1830 1831 def test_insert_beyond_index(self): 1832 Element = self.etree.Element 1833 SubElement = self.etree.SubElement 1834 1835 a = Element('a') 1836 b = SubElement(a, 'b') 1837 c = Element('c') 1838 1839 a.insert(2, c) 1840 self.assertEqual( 1841 c, 1842 a[1]) 1843 self.assertXML( 1844 _bytes('<a><b></b><c></c></a>'), 1845 a) 1846 1847 def test_insert_negative(self): 1848 Element = self.etree.Element 1849 SubElement = self.etree.SubElement 1850 1851 a = Element('a') 1852 b = SubElement(a, 'b') 1853 c = SubElement(a, 'c') 1854 1855 d = Element('d') 1856 a.insert(-1, d) 1857 self.assertEqual( 1858 d, 1859 a[-2]) 1860 self.assertXML( 1861 _bytes('<a><b></b><d></d><c></c></a>'), 1862 a) 1863 1864 def test_insert_tail(self): 1865 Element = self.etree.Element 1866 SubElement = self.etree.SubElement 1867 1868 a = Element('a') 1869 b = SubElement(a, 'b') 1870 1871 c = Element('c') 1872 c.tail = 'C2' 1873 1874 a.insert(0, c) 1875 self.assertXML( 1876 _bytes('<a><c></c>C2<b></b></a>'), 1877 a) 1878 1879 def test_remove(self): 1880 Element = self.etree.Element 1881 SubElement = self.etree.SubElement 1882 1883 a = Element('a') 1884 b = SubElement(a, 'b') 1885 c = SubElement(a, 'c') 1886 1887 a.remove(b) 1888 self.assertEqual( 1889 c, 1890 a[0]) 1891 self.assertXML( 1892 _bytes('<a><c></c></a>'), 1893 a) 1894 1895 def test_remove_ns(self): 1896 Element = self.etree.Element 1897 SubElement = self.etree.SubElement 1898 1899 a = Element('{http://test}a') 1900 b = SubElement(a, '{http://test}b') 1901 c = SubElement(a, '{http://test}c') 1902 1903 a.remove(b) 1904 self.assertXML( 1905 _bytes('<ns0:a xmlns:ns0="http://test"><ns0:c></ns0:c></ns0:a>'), 1906 a) 1907 self.assertXML( 1908 _bytes('<ns0:b xmlns:ns0="http://test"></ns0:b>'), 1909 b) 1910 1911 def test_remove_nonexisting(self): 1912 Element = self.etree.Element 1913 SubElement = self.etree.SubElement 1914 1915 a = Element('a') 1916 b = SubElement(a, 'b') 1917 c = SubElement(a, 'c') 1918 d = Element('d') 1919 self.assertRaises( 1920 ValueError, a.remove, d) 1921 1922 def test_remove_tail(self): 1923 Element = self.etree.Element 1924 SubElement = self.etree.SubElement 1925 1926 a = Element('a') 1927 b = SubElement(a, 'b') 1928 b.tail = 'b2' 1929 a.remove(b) 1930 self.assertXML( 1931 _bytes('<a></a>'), 1932 a) 1933 self.assertEqual('b2', b.tail) 1934 1935 def test_remove_while_iterating(self): 1936 # There is no guarantee that this "works", but it should 1937 # remove at least one child and not crash. 1938 Element = self.etree.Element 1939 SubElement = self.etree.SubElement 1940 1941 a = Element('a') 1942 SubElement(a, 'b') 1943 SubElement(a, 'c') 1944 SubElement(a, 'd') 1945 for el in a: 1946 a.remove(el) 1947 self.assertLess(len(a), 3) 1948 1949 def test_makeelement(self): 1950 Element = self.etree.Element 1951 1952 a = Element('a') 1953 b = a.makeelement('c', {'hoi':'dag'}) 1954 self.assertXML( 1955 _bytes('<c hoi="dag"></c>'), 1956 b) 1957 1958 required_versions_ET['test_iter'] = (1,3) 1959 def test_iter(self): 1960 Element = self.etree.Element 1961 SubElement = self.etree.SubElement 1962 1963 a = Element('a') 1964 b = SubElement(a, 'b') 1965 c = SubElement(a, 'c') 1966 d = SubElement(b, 'd') 1967 e = SubElement(c, 'e') 1968 1969 self.assertEqual( 1970 [a, b, d, c, e], 1971 list(a.iter())) 1972 self.assertEqual( 1973 [d], 1974 list(d.iter())) 1975 1976 def test_iter_remove_tail(self): 1977 Element = self.etree.Element 1978 SubElement = self.etree.SubElement 1979 1980 a = Element('a') 1981 a.text = 'a' 1982 a.tail = 'a1' * 100 1983 b = SubElement(a, 'b') 1984 b.text = 'b' 1985 b.tail = 'b1' * 100 1986 c = SubElement(a, 'c') 1987 c.text = 'c' 1988 c.tail = 'c1' * 100 1989 d = SubElement(b, 'd') 1990 d.text = 'd' 1991 d.tail = 'd1' * 100 1992 e = SubElement(c, 'e') 1993 e.text = 'e' 1994 e.tail = 'e1' * 100 1995 1996 for el in a.iter(): 1997 el.tail = None 1998 el = None 1999 2000 self.assertEqual( 2001 [None] * 5, 2002 [el.tail for el in a.iter()]) 2003 2004 def test_getslice(self): 2005 Element = self.etree.Element 2006 SubElement = self.etree.SubElement 2007 2008 a = Element('a') 2009 b = SubElement(a, 'b') 2010 c = SubElement(a, 'c') 2011 d = SubElement(a, 'd') 2012 2013 self.assertEqual( 2014 [b, c], 2015 a[0:2]) 2016 self.assertEqual( 2017 [b, c, d], 2018 a[:]) 2019 self.assertEqual( 2020 [b, c, d], 2021 a[:10]) 2022 self.assertEqual( 2023 [b], 2024 a[0:1]) 2025 self.assertEqual( 2026 [], 2027 a[10:12]) 2028 2029 def test_getslice_negative(self): 2030 Element = self.etree.Element 2031 SubElement = self.etree.SubElement 2032 2033 a = Element('a') 2034 b = SubElement(a, 'b') 2035 c = SubElement(a, 'c') 2036 d = SubElement(a, 'd') 2037 2038 self.assertEqual( 2039 [d], 2040 a[-1:]) 2041 self.assertEqual( 2042 [c, d], 2043 a[-2:]) 2044 self.assertEqual( 2045 [c], 2046 a[-2:-1]) 2047 self.assertEqual( 2048 [b, c], 2049 a[-3:-1]) 2050 self.assertEqual( 2051 [b, c], 2052 a[-3:2]) 2053 2054 def test_getslice_step(self): 2055 Element = self.etree.Element 2056 SubElement = self.etree.SubElement 2057 2058 a = Element('a') 2059 b = SubElement(a, 'b') 2060 c = SubElement(a, 'c') 2061 d = SubElement(a, 'd') 2062 e = SubElement(a, 'e') 2063 2064 self.assertEqual( 2065 [e,d,c,b], 2066 a[::-1]) 2067 self.assertEqual( 2068 [b,d], 2069 a[::2]) 2070 self.assertEqual( 2071 [e,c], 2072 a[::-2]) 2073 self.assertEqual( 2074 [d,c], 2075 a[-2:0:-1]) 2076 self.assertEqual( 2077 [e], 2078 a[:1:-2]) 2079 2080 def test_getslice_text(self): 2081 ElementTree = self.etree.ElementTree 2082 2083 f = BytesIO('<a><b>B</b>B1<c>C</c>C1</a>') 2084 doc = ElementTree(file=f) 2085 a = doc.getroot() 2086 b = a[0] 2087 c = a[1] 2088 self.assertEqual( 2089 [b, c], 2090 a[:]) 2091 self.assertEqual( 2092 [b], 2093 a[0:1]) 2094 self.assertEqual( 2095 [c], 2096 a[1:]) 2097 2098 def test_comment_getitem_getslice(self): 2099 Element = self.etree.Element 2100 Comment = self.etree.Comment 2101 SubElement = self.etree.SubElement 2102 2103 a = Element('a') 2104 b = SubElement(a, 'b') 2105 foo = Comment('foo') 2106 a.append(foo) 2107 c = SubElement(a, 'c') 2108 self.assertEqual( 2109 [b, foo, c], 2110 a[:]) 2111 self.assertEqual( 2112 foo, 2113 a[1]) 2114 a[1] = new = Element('new') 2115 self.assertEqual( 2116 new, 2117 a[1]) 2118 self.assertXML( 2119 _bytes('<a><b></b><new></new><c></c></a>'), 2120 a) 2121 2122 def test_delslice(self): 2123 Element = self.etree.Element 2124 SubElement = self.etree.SubElement 2125 2126 a = Element('a') 2127 b = SubElement(a, 'b') 2128 c = SubElement(a, 'c') 2129 d = SubElement(a, 'd') 2130 e = SubElement(a, 'e') 2131 2132 del a[1:3] 2133 self.assertEqual( 2134 [b, e], 2135 list(a)) 2136 2137 def test_delslice_negative1(self): 2138 Element = self.etree.Element 2139 SubElement = self.etree.SubElement 2140 2141 a = Element('a') 2142 b = SubElement(a, 'b') 2143 c = SubElement(a, 'c') 2144 d = SubElement(a, 'd') 2145 e = SubElement(a, 'e') 2146 2147 del a[1:-1] 2148 self.assertEqual( 2149 [b, e], 2150 list(a)) 2151 2152 def test_delslice_negative2(self): 2153 Element = self.etree.Element 2154 SubElement = self.etree.SubElement 2155 2156 a = Element('a') 2157 b = SubElement(a, 'b') 2158 c = SubElement(a, 'c') 2159 d = SubElement(a, 'd') 2160 e = SubElement(a, 'e') 2161 2162 del a[-3:-1] 2163 self.assertEqual( 2164 [b, e], 2165 list(a)) 2166 2167 def test_delslice_step(self): 2168 Element = self.etree.Element 2169 SubElement = self.etree.SubElement 2170 2171 a = Element('a') 2172 b = SubElement(a, 'b') 2173 c = SubElement(a, 'c') 2174 d = SubElement(a, 'd') 2175 e = SubElement(a, 'e') 2176 2177 del a[1::2] 2178 self.assertEqual( 2179 [b, d], 2180 list(a)) 2181 2182 def test_delslice_step_negative(self): 2183 Element = self.etree.Element 2184 SubElement = self.etree.SubElement 2185 2186 a = Element('a') 2187 b = SubElement(a, 'b') 2188 c = SubElement(a, 'c') 2189 d = SubElement(a, 'd') 2190 e = SubElement(a, 'e') 2191 2192 del a[::-1] 2193 self.assertEqual( 2194 [], 2195 list(a)) 2196 2197 def test_delslice_step_negative2(self): 2198 Element = self.etree.Element 2199 SubElement = self.etree.SubElement 2200 2201 a = Element('a') 2202 b = SubElement(a, 'b') 2203 c = SubElement(a, 'c') 2204 d = SubElement(a, 'd') 2205 e = SubElement(a, 'e') 2206 2207 del a[::-2] 2208 self.assertEqual( 2209 [b, d], 2210 list(a)) 2211 2212 def test_delslice_child_tail_dealloc(self): 2213 ElementTree = self.etree.ElementTree 2214 f = BytesIO('<a><b></b>B2<c></c>C2<d></d>D2<e></e>E2</a>') 2215 doc = ElementTree(file=f) 2216 a = doc.getroot() 2217 del a[1:3] 2218 self.assertXML( 2219 _bytes('<a><b></b>B2<e></e>E2</a>'), 2220 a) 2221 2222 def test_delslice_child_tail(self): 2223 ElementTree = self.etree.ElementTree 2224 f = BytesIO('<a><b></b>B2<c></c>C2<d></d>D2<e></e>E2</a>') 2225 doc = ElementTree(file=f) 2226 a = doc.getroot() 2227 b, c, d, e = a 2228 del a[1:3] 2229 self.assertXML( 2230 _bytes('<a><b></b>B2<e></e>E2</a>'), 2231 a) 2232 self.assertEqual("B2", b.tail) 2233 self.assertEqual("C2", c.tail) 2234 self.assertEqual("D2", d.tail) 2235 self.assertEqual("E2", e.tail) 2236 2237 def test_delslice_tail(self): 2238 XML = self.etree.XML 2239 a = XML(_bytes('<a><b></b>B2<c></c>C2</a>')) 2240 b, c = a 2241 2242 del a[:] 2243 2244 self.assertEqual("B2", b.tail) 2245 self.assertEqual("C2", c.tail) 2246 2247 def test_delslice_memory(self): 2248 # this could trigger a crash 2249 Element = self.etree.Element 2250 SubElement = self.etree.SubElement 2251 a = Element('a') 2252 b = SubElement(a, 'b') 2253 c = SubElement(b, 'c') 2254 del b # no more reference to b 2255 del a[:] 2256 self.assertEqual('c', c.tag) 2257 2258 def test_setslice(self): 2259 Element = self.etree.Element 2260 SubElement = self.etree.SubElement 2261 2262 a = Element('a') 2263 b = SubElement(a, 'b') 2264 c = SubElement(a, 'c') 2265 d = SubElement(a, 'd') 2266 2267 e = Element('e') 2268 f = Element('f') 2269 g = Element('g') 2270 2271 s = [e, f, g] 2272 a[1:2] = s 2273 self.assertEqual( 2274 [b, e, f, g, d], 2275 list(a)) 2276 2277 def test_setslice_all(self): 2278 Element = self.etree.Element 2279 SubElement = self.etree.SubElement 2280 2281 a = Element('a') 2282 b = SubElement(a, 'b') 2283 c = SubElement(a, 'c') 2284 2285 e = Element('e') 2286 f = Element('f') 2287 g = Element('g') 2288 2289 s = [e, f, g] 2290 a[:] = s 2291 self.assertEqual( 2292 [e, f, g], 2293 list(a)) 2294 2295 def test_setslice_all_empty(self): 2296 Element = self.etree.Element 2297 SubElement = self.etree.SubElement 2298 2299 a = Element('a') 2300 2301 e = Element('e') 2302 f = Element('f') 2303 g = Element('g') 2304 2305 s = [e, f, g] 2306 a[:] = s 2307 self.assertEqual( 2308 [e, f, g], 2309 list(a)) 2310 2311 def test_setslice_all_replace(self): 2312 Element = self.etree.Element 2313 SubElement = self.etree.SubElement 2314 2315 a = Element('a') 2316 b = SubElement(a, 'b') 2317 c = SubElement(a, 'c') 2318 d = SubElement(a, 'd') 2319 2320 s = [b, c, d] 2321 a[:] = s 2322 self.assertEqual( 2323 [b, c, d], 2324 list(a)) 2325 2326 def test_setslice_all_replace_reversed(self): 2327 Element = self.etree.Element 2328 SubElement = self.etree.SubElement 2329 2330 a = Element('a') 2331 b = SubElement(a, 'b') 2332 c = SubElement(a, 'c') 2333 d = SubElement(a, 'd') 2334 2335 s = [d, c, b] 2336 a[:] = s 2337 self.assertEqual( 2338 [d, c, b], 2339 list(a)) 2340 2341 def test_setslice_all_replace_reversed_ns1(self): 2342 Element = self.etree.Element 2343 SubElement = self.etree.SubElement 2344 2345 a = Element('{ns}a') 2346 b = SubElement(a, '{ns}b', {'{ns1}a1': 'test'}) 2347 c = SubElement(a, '{ns}c', {'{ns2}a2': 'test'}) 2348 d = SubElement(a, '{ns}d', {'{ns3}a3': 'test'}) 2349 2350 s = [d, c, b] 2351 a[:] = s 2352 self.assertEqual( 2353 [d, c, b], 2354 list(a)) 2355 self.assertEqual( 2356 ['{ns}d', '{ns}c', '{ns}b'], 2357 [ child.tag for child in a ]) 2358 2359 self.assertEqual( 2360 [['{ns3}a3'], ['{ns2}a2'], ['{ns1}a1']], 2361 [ list(child.attrib.keys()) for child in a ]) 2362 2363 def test_setslice_all_replace_reversed_ns2(self): 2364 Element = self.etree.Element 2365 SubElement = self.etree.SubElement 2366 2367 a = Element('{ns}a') 2368 b = SubElement(a, '{ns1}b', {'{ns}a1': 'test'}) 2369 c = SubElement(a, '{ns2}c', {'{ns}a2': 'test'}) 2370 d = SubElement(a, '{ns3}d', {'{ns}a3': 'test'}) 2371 2372 s = [d, c, b] 2373 a[:] = s 2374 self.assertEqual( 2375 [d, c, b], 2376 list(a)) 2377 self.assertEqual( 2378 ['{ns3}d', '{ns2}c', '{ns1}b'], 2379 [ child.tag for child in a ]) 2380 2381 self.assertEqual( 2382 [['{ns}a3'], ['{ns}a2'], ['{ns}a1']], 2383 [ list(child.attrib.keys()) for child in a ]) 2384 2385 def test_setslice_end(self): 2386 Element = self.etree.Element 2387 SubElement = self.etree.SubElement 2388 2389 a = Element('a') 2390 b = SubElement(a, 'b') 2391 c = SubElement(a, 'c') 2392 2393 e = Element('e') 2394 f = Element('f') 2395 g = Element('g') 2396 h = Element('h') 2397 2398 s = [e, f] 2399 a[99:] = s 2400 self.assertEqual( 2401 [b, c, e, f], 2402 list(a)) 2403 2404 s = [g, h] 2405 a[:0] = s 2406 self.assertEqual( 2407 [g, h, b, c, e, f], 2408 list(a)) 2409 2410 def test_setslice_end_exact(self): 2411 Element = self.etree.Element 2412 SubElement = self.etree.SubElement 2413 2414 a = Element('a') 2415 b = SubElement(a, 'b') 2416 c = SubElement(a, 'c') 2417 d = SubElement(a, 'd') 2418 2419 e = Element('e') 2420 f = Element('f') 2421 g = Element('g') 2422 2423 s = [e, f, g] 2424 a[3:] = s 2425 self.assertEqual( 2426 [b, c, d, e, f, g], 2427 list(a)) 2428 2429 def test_setslice_single(self): 2430 Element = self.etree.Element 2431 SubElement = self.etree.SubElement 2432 2433 a = Element('a') 2434 b = SubElement(a, 'b') 2435 c = SubElement(a, 'c') 2436 2437 e = Element('e') 2438 f = Element('f') 2439 2440 s = [e] 2441 a[0:1] = s 2442 self.assertEqual( 2443 [e, c], 2444 list(a)) 2445 2446 s = [f] 2447 a[1:2] = s 2448 self.assertEqual( 2449 [e, f], 2450 list(a)) 2451 2452 def test_setslice_tail(self): 2453 ElementTree = self.etree.ElementTree 2454 Element = self.etree.Element 2455 f = BytesIO('<a><b></b>B2<c></c>C2<d></d>D2<e></e>E2</a>') 2456 doc = ElementTree(file=f) 2457 a = doc.getroot() 2458 x = Element('x') 2459 y = Element('y') 2460 z = Element('z') 2461 x.tail = 'X2' 2462 y.tail = 'Y2' 2463 z.tail = 'Z2' 2464 a[1:3] = [x, y, z] 2465 self.assertXML( 2466 _bytes('<a><b></b>B2<x></x>X2<y></y>Y2<z></z>Z2<e></e>E2</a>'), 2467 a) 2468 2469 def test_setslice_negative(self): 2470 Element = self.etree.Element 2471 SubElement = self.etree.SubElement 2472 2473 a = Element('a') 2474 b = SubElement(a, 'b') 2475 c = SubElement(a, 'c') 2476 d = SubElement(a, 'd') 2477 2478 x = Element('x') 2479 y = Element('y') 2480 2481 a[1:-1] = [x, y] 2482 self.assertEqual( 2483 [b, x, y, d], 2484 list(a)) 2485 2486 def test_setslice_negative2(self): 2487 Element = self.etree.Element 2488 SubElement = self.etree.SubElement 2489 2490 a = Element('a') 2491 b = SubElement(a, 'b') 2492 c = SubElement(a, 'c') 2493 d = SubElement(a, 'd') 2494 2495 x = Element('x') 2496 y = Element('y') 2497 2498 a[1:-2] = [x, y] 2499 self.assertEqual( 2500 [b, x, y, c, d], 2501 list(a)) 2502 2503 def test_setslice_empty(self): 2504 Element = self.etree.Element 2505 2506 a = Element('a') 2507 2508 b = Element('b') 2509 c = Element('c') 2510 2511 a[:] = [b, c] 2512 self.assertEqual( 2513 [b, c], 2514 list(a)) 2515 2516 def test_tail_elementtree_root(self): 2517 Element = self.etree.Element 2518 ElementTree = self.etree.ElementTree 2519 2520 a = Element('a') 2521 a.tail = 'A2' 2522 t = ElementTree(element=a) 2523 self.assertEqual('A2', 2524 a.tail) 2525 2526 def test_ns_access(self): 2527 ElementTree = self.etree.ElementTree 2528 ns = 'http://xml.infrae.com/1' 2529 f = BytesIO('<x:a xmlns:x="%s"><x:b></x:b></x:a>' % ns) 2530 t = ElementTree(file=f) 2531 a = t.getroot() 2532 self.assertEqual('{%s}a' % ns, 2533 a.tag) 2534 self.assertEqual('{%s}b' % ns, 2535 a[0].tag) 2536 2537 def test_ns_access2(self): 2538 ElementTree = self.etree.ElementTree 2539 ns = 'http://xml.infrae.com/1' 2540 ns2 = 'http://xml.infrae.com/2' 2541 f = BytesIO('<x:a xmlns:x="%s" xmlns:y="%s"><x:b></x:b><y:b></y:b></x:a>' % (ns, ns2)) 2542 t = ElementTree(file=f) 2543 a = t.getroot() 2544 self.assertEqual('{%s}a' % ns, 2545 a.tag) 2546 self.assertEqual('{%s}b' % ns, 2547 a[0].tag) 2548 self.assertEqual('{%s}b' % ns2, 2549 a[1].tag) 2550 2551 def test_ns_setting(self): 2552 Element = self.etree.Element 2553 SubElement = self.etree.SubElement 2554 ns = 'http://xml.infrae.com/1' 2555 ns2 = 'http://xml.infrae.com/2' 2556 a = Element('{%s}a' % ns) 2557 b = SubElement(a, '{%s}b' % ns2) 2558 c = SubElement(a, '{%s}c' % ns) 2559 self.assertEqual('{%s}a' % ns, 2560 a.tag) 2561 self.assertEqual('{%s}b' % ns2, 2562 b.tag) 2563 self.assertEqual('{%s}c' % ns, 2564 c.tag) 2565 self.assertEqual('{%s}a' % ns, 2566 a.tag) 2567 self.assertEqual('{%s}b' % ns2, 2568 b.tag) 2569 self.assertEqual('{%s}c' % ns, 2570 c.tag) 2571 2572 def test_ns_tag_parse(self): 2573 Element = self.etree.Element 2574 SubElement = self.etree.SubElement 2575 ElementTree = self.etree.ElementTree 2576 2577 ns = 'http://xml.infrae.com/1' 2578 ns2 = 'http://xml.infrae.com/2' 2579 f = BytesIO('<a xmlns="%s" xmlns:x="%s"><x:b></x:b><b></b></a>' % (ns, ns2)) 2580 t = ElementTree(file=f) 2581 2582 a = t.getroot() 2583 self.assertEqual('{%s}a' % ns, 2584 a.tag) 2585 self.assertEqual('{%s}b' % ns2, 2586 a[0].tag) 2587 self.assertEqual('{%s}b' % ns, 2588 a[1].tag) 2589 2590 def test_ns_attr(self): 2591 Element = self.etree.Element 2592 ns = 'http://xml.infrae.com/1' 2593 ns2 = 'http://xml.infrae.com/2' 2594 a = Element('a') 2595 a.set('{%s}foo' % ns, 'Foo') 2596 a.set('{%s}bar' % ns2, 'Bar') 2597 self.assertEqual( 2598 'Foo', 2599 a.get('{%s}foo' % ns)) 2600 self.assertEqual( 2601 'Bar', 2602 a.get('{%s}bar' % ns2)) 2603 try: 2604 self.assertXML( 2605 _bytes('<a xmlns:ns0="%s" xmlns:ns1="%s" ns0:foo="Foo" ns1:bar="Bar"></a>' % (ns, ns2)), 2606 a) 2607 except AssertionError: 2608 self.assertXML( 2609 _bytes('<a xmlns:ns0="%s" xmlns:ns1="%s" ns1:foo="Foo" ns0:bar="Bar"></a>' % (ns2, ns)), 2610 a) 2611 2612 def test_ns_move(self): 2613 Element = self.etree.Element 2614 one = self.etree.fromstring( 2615 _bytes('<foo><bar xmlns:ns="http://a.b.c"><ns:baz/></bar></foo>')) 2616 baz = one[0][0] 2617 2618 two = Element('root') 2619 two.append(baz) 2620 # removing the originating document could cause a crash/error before 2621 # as namespace is not moved along with it 2622 del one, baz 2623 self.assertEqual('{http://a.b.c}baz', two[0].tag) 2624 2625 def test_ns_decl_tostring(self): 2626 tostring = self.etree.tostring 2627 root = self.etree.XML( 2628 _bytes('<foo><bar xmlns:ns="http://a.b.c"><ns:baz/></bar></foo>')) 2629 baz = root[0][0] 2630 2631 nsdecl = re.findall(_bytes("xmlns(?::[a-z0-9]+)?=[\"']([^\"']+)[\"']"), 2632 tostring(baz)) 2633 self.assertEqual([_bytes("http://a.b.c")], nsdecl) 2634 2635 def test_ns_decl_tostring_default(self): 2636 tostring = self.etree.tostring 2637 root = self.etree.XML( 2638 _bytes('<foo><bar xmlns="http://a.b.c"><baz/></bar></foo>')) 2639 baz = root[0][0] 2640 2641 nsdecl = re.findall(_bytes("xmlns(?::[a-z0-9]+)?=[\"']([^\"']+)[\"']"), 2642 tostring(baz)) 2643 self.assertEqual([_bytes("http://a.b.c")], nsdecl) 2644 2645 def test_ns_decl_tostring_root(self): 2646 tostring = self.etree.tostring 2647 root = self.etree.XML( 2648 _bytes('<foo xmlns:ns="http://a.b.c"><bar><ns:baz/></bar></foo>')) 2649 baz = root[0][0] 2650 2651 nsdecl = re.findall(_bytes("xmlns(?::[a-z0-9]+)?=[\"']([^\"']+)[\"']"), 2652 tostring(baz)) 2653 2654 self.assertEqual([_bytes("http://a.b.c")], nsdecl) 2655 2656 def test_ns_decl_tostring_element(self): 2657 Element = self.etree.Element 2658 SubElement = self.etree.SubElement 2659 2660 root = Element("foo") 2661 bar = SubElement(root, "{http://a.b.c}bar") 2662 baz = SubElement(bar, "{http://a.b.c}baz") 2663 2664 nsdecl = re.findall(_bytes("xmlns(?::[a-z0-9]+)?=[\"']([^\"']+)[\"']"), 2665 self.etree.tostring(baz)) 2666 2667 self.assertEqual([_bytes("http://a.b.c")], nsdecl) 2668 2669 def test_attribute_xmlns_move(self): 2670 Element = self.etree.Element 2671 2672 root = Element('element') 2673 2674 subelement = Element('subelement', 2675 {"{http://www.w3.org/XML/1998/namespace}id": "foo"}) 2676 self.assertEqual(1, len(subelement.attrib)) 2677 self.assertEqual( 2678 "foo", 2679 subelement.get("{http://www.w3.org/XML/1998/namespace}id")) 2680 2681 root.append(subelement) 2682 self.assertEqual(1, len(subelement.attrib)) 2683 self.assertEqual( 2684 list({"{http://www.w3.org/XML/1998/namespace}id" : "foo"}.items()), 2685 list(subelement.attrib.items())) 2686 self.assertEqual( 2687 "foo", 2688 subelement.get("{http://www.w3.org/XML/1998/namespace}id")) 2689 2690 def test_namespaces_after_serialize(self): 2691 parse = self.etree.parse 2692 tostring = self.etree.tostring 2693 2694 ns_href = "http://a.b.c" 2695 one = parse( 2696 BytesIO('<foo><bar xmlns:ns="%s"><ns:baz/></bar></foo>' % ns_href)) 2697 baz = one.getroot()[0][0] 2698 2699 parsed = parse(BytesIO( tostring(baz) )).getroot() 2700 self.assertEqual('{%s}baz' % ns_href, parsed.tag) 2701 2702 def test_attribute_namespace_roundtrip(self): 2703 fromstring = self.etree.fromstring 2704 tostring = self.etree.tostring 2705 2706 ns_href = "http://a.b.c" 2707 xml = _bytes('<root xmlns="%s" xmlns:x="%s"><el x:a="test" /></root>' % ( 2708 ns_href,ns_href)) 2709 root = fromstring(xml) 2710 self.assertEqual('test', root[0].get('{%s}a' % ns_href)) 2711 2712 xml2 = tostring(root) 2713 self.assertTrue(_bytes(':a=') in xml2, xml2) 2714 2715 root2 = fromstring(xml2) 2716 self.assertEqual('test', root2[0].get('{%s}a' % ns_href)) 2717 2718 def test_attribute_namespace_roundtrip_replaced(self): 2719 fromstring = self.etree.fromstring 2720 tostring = self.etree.tostring 2721 2722 ns_href = "http://a.b.c" 2723 xml = _bytes('<root xmlns="%s" xmlns:x="%s"><el x:a="test" /></root>' % ( 2724 ns_href,ns_href)) 2725 root = fromstring(xml) 2726 self.assertEqual('test', root[0].get('{%s}a' % ns_href)) 2727 2728 root[0].set('{%s}a' % ns_href, 'TEST') 2729 2730 xml2 = tostring(root) 2731 self.assertTrue(_bytes(':a=') in xml2, xml2) 2732 2733 root2 = fromstring(xml2) 2734 self.assertEqual('TEST', root2[0].get('{%s}a' % ns_href)) 2735 2736 required_versions_ET['test_register_namespace'] = (1,3) 2737 def test_register_namespace(self): 2738 # ET 1.3+ 2739 Element = self.etree.Element 2740 prefix = 'TESTPREFIX' 2741 namespace = 'http://seriously.unknown/namespace/URI' 2742 2743 el = Element('{%s}test' % namespace) 2744 self.assertEqual(_bytes('<ns0:test xmlns:ns0="%s"></ns0:test>' % namespace), 2745 self._writeElement(el)) 2746 2747 self.etree.register_namespace(prefix, namespace) 2748 el = Element('{%s}test' % namespace) 2749 self.assertEqual(_bytes('<%s:test xmlns:%s="%s"></%s:test>' % ( 2750 prefix, prefix, namespace, prefix)), 2751 self._writeElement(el)) 2752 2753 self.assertRaises(ValueError, self.etree.register_namespace, 'ns25', namespace) 2754 2755 def test_tostring(self): 2756 tostring = self.etree.tostring 2757 Element = self.etree.Element 2758 SubElement = self.etree.SubElement 2759 2760 a = Element('a') 2761 b = SubElement(a, 'b') 2762 c = SubElement(a, 'c') 2763 2764 self.assertEqual(_bytes('<a><b></b><c></c></a>'), 2765 canonicalize(tostring(a))) 2766 2767 def test_tostring_element(self): 2768 tostring = self.etree.tostring 2769 Element = self.etree.Element 2770 SubElement = self.etree.SubElement 2771 2772 a = Element('a') 2773 b = SubElement(a, 'b') 2774 c = SubElement(a, 'c') 2775 d = SubElement(c, 'd') 2776 self.assertEqual(_bytes('<b></b>'), 2777 canonicalize(tostring(b))) 2778 self.assertEqual(_bytes('<c><d></d></c>'), 2779 canonicalize(tostring(c))) 2780 2781 def test_tostring_element_tail(self): 2782 tostring = self.etree.tostring 2783 Element = self.etree.Element 2784 SubElement = self.etree.SubElement 2785 2786 a = Element('a') 2787 b = SubElement(a, 'b') 2788 c = SubElement(a, 'c') 2789 d = SubElement(c, 'd') 2790 b.tail = 'Foo' 2791 2792 self.assertTrue(tostring(b) == _bytes('<b/>Foo') or 2793 tostring(b) == _bytes('<b />Foo')) 2794 2795 required_versions_ET['test_tostring_method_html'] = (1,3) 2796 def test_tostring_method_html(self): 2797 tostring = self.etree.tostring 2798 Element = self.etree.Element 2799 SubElement = self.etree.SubElement 2800 2801 html = Element('html') 2802 body = SubElement(html, 'body') 2803 p = SubElement(body, 'p') 2804 p.text = "html" 2805 SubElement(p, 'br').tail = "test" 2806 2807 self.assertEqual(_bytes('<html><body><p>html<br>test</p></body></html>'), 2808 tostring(html, method="html")) 2809 2810 required_versions_ET['test_tostring_method_text'] = (1,3) 2811 def test_tostring_method_text(self): 2812 tostring = self.etree.tostring 2813 Element = self.etree.Element 2814 SubElement = self.etree.SubElement 2815 2816 a = Element('a') 2817 a.text = "A" 2818 a.tail = "tail" 2819 b = SubElement(a, 'b') 2820 b.text = "B" 2821 b.tail = "TAIL" 2822 c = SubElement(a, 'c') 2823 c.text = "C" 2824 2825 self.assertEqual(_bytes('ABTAILCtail'), 2826 tostring(a, method="text")) 2827 2828 def test_iterparse(self): 2829 iterparse = self.etree.iterparse 2830 f = BytesIO('<a><b></b><c/></a>') 2831 2832 iterator = iterparse(f) 2833 self.assertEqual(None, 2834 iterator.root) 2835 events = list(iterator) 2836 root = iterator.root 2837 self.assertEqual( 2838 [('end', root[0]), ('end', root[1]), ('end', root)], 2839 events) 2840 2841 def test_iterparse_incomplete(self): 2842 iterparse = self.etree.iterparse 2843 f = BytesIO('<a><b></b><c/></a>') 2844 2845 iterator = iterparse(f) 2846 self.assertEqual(None, 2847 iterator.root) 2848 event, element = next(iter(iterator)) 2849 self.assertEqual('end', event) 2850 self.assertEqual('b', element.tag) 2851 2852 def test_iterparse_file(self): 2853 iterparse = self.etree.iterparse 2854 iterator = iterparse(fileInTestDir("test.xml")) 2855 self.assertEqual(None, 2856 iterator.root) 2857 events = list(iterator) 2858 root = iterator.root 2859 self.assertEqual( 2860 [('end', root[0]), ('end', root)], 2861 events) 2862 2863 def test_iterparse_start(self): 2864 iterparse = self.etree.iterparse 2865 f = BytesIO('<a><b></b><c/></a>') 2866 2867 iterator = iterparse(f, events=('start',)) 2868 events = list(iterator) 2869 root = iterator.root 2870 self.assertEqual( 2871 [('start', root), ('start', root[0]), ('start', root[1])], 2872 events) 2873 2874 def test_iterparse_start_end(self): 2875 iterparse = self.etree.iterparse 2876 f = BytesIO('<a><b></b><c/></a>') 2877 2878 iterator = iterparse(f, events=('start','end')) 2879 events = list(iterator) 2880 root = iterator.root 2881 self.assertEqual( 2882 [('start', root), ('start', root[0]), ('end', root[0]), 2883 ('start', root[1]), ('end', root[1]), ('end', root)], 2884 events) 2885 2886 def test_iterparse_clear(self): 2887 iterparse = self.etree.iterparse 2888 f = BytesIO('<a><b></b><c/></a>') 2889 2890 iterator = iterparse(f) 2891 for event, elem in iterator: 2892 elem.clear() 2893 2894 root = iterator.root 2895 self.assertEqual(0, 2896 len(root)) 2897 2898 def test_iterparse_large(self): 2899 iterparse = self.etree.iterparse 2900 CHILD_COUNT = 12345 2901 f = BytesIO('<a>%s</a>' % ('<b>test</b>'*CHILD_COUNT)) 2902 2903 i = 0 2904 for key in iterparse(f): 2905 event, element = key 2906 i += 1 2907 self.assertEqual(i, CHILD_COUNT + 1) 2908 2909 def test_iterparse_set_ns_attribute(self): 2910 iterparse = self.etree.iterparse 2911 f = BytesIO('<a xmlns="http://ns1/"><b><c xmlns="http://ns2/"/></b></a>') 2912 2913 attr_name = '{http://testns/}bla' 2914 events = [] 2915 iterator = iterparse(f, events=('start','end','start-ns','end-ns')) 2916 for event, elem in iterator: 2917 events.append(event) 2918 if event == 'start': 2919 if elem.tag != '{http://ns1/}a': 2920 elem.set(attr_name, 'value') 2921 2922 self.assertEqual( 2923 ['start-ns', 'start', 'start', 'start-ns', 'start', 2924 'end', 'end-ns', 'end', 'end', 'end-ns'], 2925 events) 2926 2927 root = iterator.root 2928 self.assertEqual( 2929 None, 2930 root.get(attr_name)) 2931 self.assertEqual( 2932 'value', 2933 root[0].get(attr_name)) 2934 2935 def test_iterparse_only_end_ns(self): 2936 iterparse = self.etree.iterparse 2937 f = BytesIO('<a xmlns="http://ns1/"><b><c xmlns="http://ns2/"/></b></a>') 2938 2939 attr_name = '{http://testns/}bla' 2940 events = [] 2941 iterator = iterparse(f, events=('start','end','start-ns','end-ns')) 2942 for event, elem in iterator: 2943 events.append(event) 2944 if event == 'start': 2945 if elem.tag != '{http://ns1/}a': 2946 elem.set(attr_name, 'value') 2947 2948 self.assertEqual( 2949 ['start-ns', 'start', 'start', 'start-ns', 'start', 2950 'end', 'end-ns', 'end', 'end', 'end-ns'], 2951 events) 2952 2953 root = iterator.root 2954 self.assertEqual( 2955 None, 2956 root.get(attr_name)) 2957 self.assertEqual( 2958 'value', 2959 root[0].get(attr_name)) 2960 2961 def test_iterparse_move_elements(self): 2962 iterparse = self.etree.iterparse 2963 f = BytesIO('<a><b><d/></b><c/></a>') 2964 2965 for event, node in etree.iterparse(f): pass 2966 2967 root = etree.Element('new_root', {}) 2968 root[:] = node[:] 2969 2970 self.assertEqual( 2971 ['b', 'c'], 2972 [ el.tag for el in root ]) 2973 2974 def test_iterparse_cdata(self): 2975 tostring = self.etree.tostring 2976 f = BytesIO('<root><![CDATA[test]]></root>') 2977 context = self.etree.iterparse(f) 2978 content = [ el.text for event,el in context ] 2979 2980 self.assertEqual(['test'], content) 2981 self.assertEqual(_bytes('<root>test</root>'), 2982 tostring(context.root)) 2983 2984 def test_parse_file(self): 2985 parse = self.etree.parse 2986 # from file 2987 tree = parse(fileInTestDir('test.xml')) 2988 self.assertXML( 2989 _bytes('<a><b></b></a>'), 2990 tree.getroot()) 2991 2992 def test_parse_file_nonexistent(self): 2993 parse = self.etree.parse 2994 self.assertRaises(IOError, parse, fileInTestDir('notthere.xml')) 2995 2996 def test_parse_error_none(self): 2997 parse = self.etree.parse 2998 self.assertRaises(TypeError, parse, None) 2999 3000 required_versions_ET['test_parse_error'] = (1,3) 3001 def test_parse_error(self): 3002 # ET < 1.3 raises ExpatError 3003 parse = self.etree.parse 3004 f = BytesIO('<a><b></c></b></a>') 3005 self.assertRaises(SyntaxError, parse, f) 3006 f.close() 3007 3008 required_versions_ET['test_parse_error_from_file'] = (1,3) 3009 def test_parse_error_from_file(self): 3010 parse = self.etree.parse 3011 # from file 3012 f = open(fileInTestDir('test_broken.xml'), 'rb') 3013 self.assertRaises(SyntaxError, parse, f) 3014 f.close() 3015 3016 def test_parse_file_object(self): 3017 parse = self.etree.parse 3018 # from file object 3019 f = open(fileInTestDir('test.xml'), 'rb') 3020 tree = parse(f) 3021 f.close() 3022 self.assertXML( 3023 _bytes('<a><b></b></a>'), 3024 tree.getroot()) 3025 3026 def test_parse_stringio(self): 3027 parse = self.etree.parse 3028 f = BytesIO('<a><b></b></a>') 3029 tree = parse(f) 3030 f.close() 3031 self.assertXML( 3032 _bytes('<a><b></b></a>'), 3033 tree.getroot() 3034 ) 3035 3036 def test_parse_cdata(self): 3037 tostring = self.etree.tostring 3038 root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>')) 3039 3040 self.assertEqual('test', root.text) 3041 self.assertEqual(_bytes('<root>test</root>'), 3042 tostring(root)) 3043 3044 def test_parse_with_encoding(self): 3045 # this can fail in libxml2 <= 2.6.22 3046 parse = self.etree.parse 3047 tree = parse(BytesIO('<?xml version="1.0" encoding="ascii"?><html/>')) 3048 self.assertXML(_bytes('<html></html>'), 3049 tree.getroot()) 3050 3051 def test_encoding(self): 3052 Element = self.etree.Element 3053 3054 a = Element('a') 3055 a.text = _str('Søk på nettet') 3056 self.assertXML( 3057 _str('<a>Søk på nettet</a>').encode('UTF-8'), 3058 a, 'utf-8') 3059 3060 def test_encoding_exact(self): 3061 ElementTree = self.etree.ElementTree 3062 Element = self.etree.Element 3063 3064 a = Element('a') 3065 a.text = _str('Søk på nettet') 3066 3067 f = BytesIO() 3068 tree = ElementTree(element=a) 3069 tree.write(f, encoding='utf-8') 3070 self.assertEqual(_str('<a>Søk på nettet</a>').encode('UTF-8'), 3071 f.getvalue().replace(_bytes('\n'),_bytes(''))) 3072 3073 def test_parse_file_encoding(self): 3074 parse = self.etree.parse 3075 # from file 3076 tree = parse(fileInTestDir('test-string.xml')) 3077 self.assertXML( 3078 _str('<a>Søk på nettet</a>').encode('UTF-8'), 3079 tree.getroot(), 'UTF-8') 3080 3081 def test_parse_file_object_encoding(self): 3082 parse = self.etree.parse 3083 # from file object 3084 f = open(fileInTestDir('test-string.xml'), 'rb') 3085 tree = parse(f) 3086 f.close() 3087 self.assertXML( 3088 _str('<a>Søk på nettet</a>').encode('UTF-8'), 3089 tree.getroot(), 'UTF-8') 3090 3091 def test_encoding_8bit_latin1(self): 3092 ElementTree = self.etree.ElementTree 3093 Element = self.etree.Element 3094 3095 a = Element('a') 3096 a.text = _str('Søk på nettet') 3097 3098 f = BytesIO() 3099 tree = ElementTree(element=a) 3100 tree.write(f, encoding='iso-8859-1') 3101 result = f.getvalue() 3102 declaration = _bytes("<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>") 3103 self.assertEncodingDeclaration(result, _bytes('iso-8859-1')) 3104 result = result.split(_bytes('?>'), 1)[-1].replace(_bytes('\n'),_bytes('')) 3105 self.assertEqual(_str('<a>Søk på nettet</a>').encode('iso-8859-1'), 3106 result) 3107 3108 required_versions_ET['test_parse_encoding_8bit_explicit'] = (1,3) 3109 def test_parse_encoding_8bit_explicit(self): 3110 XMLParser = self.XMLParser 3111 3112 text = _str('Søk på nettet') 3113 xml_latin1 = (_str('<a>%s</a>') % text).encode('iso-8859-1') 3114 3115 self.assertRaises(self.etree.ParseError, 3116 self.etree.parse, 3117 BytesIO(xml_latin1)) 3118 3119 tree = self.etree.parse(BytesIO(xml_latin1), 3120 XMLParser(encoding="iso-8859-1")) 3121 a = tree.getroot() 3122 self.assertEqual(a.text, text) 3123 3124 required_versions_ET['test_parse_encoding_8bit_override'] = (1,3) 3125 def test_parse_encoding_8bit_override(self): 3126 XMLParser = self.XMLParser 3127 3128 text = _str('Søk på nettet') 3129 wrong_declaration = _str("<?xml version='1.0' encoding='UTF-8'?>") 3130 xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text) 3131 ).encode('iso-8859-1') 3132 3133 self.assertRaises(self.etree.ParseError, 3134 self.etree.parse, 3135 BytesIO(xml_latin1)) 3136 3137 tree = self.etree.parse(BytesIO(xml_latin1), 3138 XMLParser(encoding="iso-8859-1")) 3139 a = tree.getroot() 3140 self.assertEqual(a.text, text) 3141 3142 def _test_wrong_unicode_encoding(self): 3143 # raise error on wrong encoding declaration in unicode strings 3144 XML = self.etree.XML 3145 test_utf = (_str('<?xml version="1.0" encoding="iso-8859-1"?>') + 3146 _str('<a>Søk på nettet</a>')) 3147 self.assertRaises(SyntaxError, XML, test_utf) 3148 3149 def test_encoding_write_default_encoding(self): 3150 ElementTree = self.etree.ElementTree 3151 Element = self.etree.Element 3152 3153 a = Element('a') 3154 a.text = _str('Søk på nettet') 3155 3156 f = BytesIO() 3157 tree = ElementTree(element=a) 3158 tree.write(f) 3159 data = f.getvalue().replace(_bytes('\n'),_bytes('')) 3160 self.assertEqual( 3161 _str('<a>Søk på nettet</a>').encode('ASCII', 'xmlcharrefreplace'), 3162 data) 3163 3164 def test_encoding_tostring(self): 3165 Element = self.etree.Element 3166 tostring = self.etree.tostring 3167 3168 a = Element('a') 3169 a.text = _str('Søk på nettet') 3170 self.assertEqual(_str('<a>Søk på nettet</a>').encode('UTF-8'), 3171 tostring(a, encoding='utf-8')) 3172 3173 def test_encoding_tostring_unknown(self): 3174 Element = self.etree.Element 3175 tostring = self.etree.tostring 3176 3177 a = Element('a') 3178 a.text = _str('Søk på nettet') 3179 self.assertRaises(LookupError, tostring, a, 3180 encoding='Invalid Encoding') 3181 3182 def test_encoding_tostring_sub(self): 3183 Element = self.etree.Element 3184 SubElement = self.etree.SubElement 3185 tostring = self.etree.tostring 3186 3187 a = Element('a') 3188 b = SubElement(a, 'b') 3189 b.text = _str('Søk på nettet') 3190 self.assertEqual(_str('<b>Søk på nettet</b>').encode('UTF-8'), 3191 tostring(b, encoding='utf-8')) 3192 3193 def test_encoding_tostring_sub_tail(self): 3194 Element = self.etree.Element 3195 SubElement = self.etree.SubElement 3196 tostring = self.etree.tostring 3197 3198 a = Element('a') 3199 b = SubElement(a, 'b') 3200 b.text = _str('Søk på nettet') 3201 b.tail = _str('Søk') 3202 self.assertEqual(_str('<b>Søk på nettet</b>Søk').encode('UTF-8'), 3203 tostring(b, encoding='utf-8')) 3204 3205 def test_encoding_tostring_default_encoding(self): 3206 Element = self.etree.Element 3207 SubElement = self.etree.SubElement 3208 tostring = self.etree.tostring 3209 3210 a = Element('a') 3211 a.text = _str('Søk på nettet') 3212 3213 expected = _bytes('<a>Søk på nettet</a>') 3214 self.assertEqual( 3215 expected, 3216 tostring(a)) 3217 3218 def test_encoding_sub_tostring_default_encoding(self): 3219 Element = self.etree.Element 3220 SubElement = self.etree.SubElement 3221 tostring = self.etree.tostring 3222 3223 a = Element('a') 3224 b = SubElement(a, 'b') 3225 b.text = _str('Søk på nettet') 3226 3227 expected = _bytes('<b>Søk på nettet</b>') 3228 self.assertEqual( 3229 expected, 3230 tostring(b)) 3231 3232 def test_encoding_8bit_xml(self): 3233 utext = _str('Søk på nettet') 3234 uxml = _str('<p>%s</p>') % utext 3235 prologue = _bytes('<?xml version="1.0" encoding="iso-8859-1" ?>') 3236 isoxml = prologue + uxml.encode('iso-8859-1') 3237 tree = self.etree.XML(isoxml) 3238 self.assertEqual(utext, tree.text) 3239 3240 def test_encoding_utf8_bom(self): 3241 utext = _str('Søk på nettet') 3242 uxml = (_str('<?xml version="1.0" encoding="UTF-8"?>') + 3243 _str('<p>%s</p>') % utext) 3244 bom = _bytes('\\xEF\\xBB\\xBF').decode("unicode_escape").encode("latin1") 3245 xml = bom + uxml.encode("utf-8") 3246 tree = etree.XML(xml) 3247 self.assertEqual(utext, tree.text) 3248 3249 def test_encoding_8bit_parse_stringio(self): 3250 utext = _str('Søk på nettet') 3251 uxml = _str('<p>%s</p>') % utext 3252 prologue = _bytes('<?xml version="1.0" encoding="iso-8859-1" ?>') 3253 isoxml = prologue + uxml.encode('iso-8859-1') 3254 el = self.etree.parse(BytesIO(isoxml)).getroot() 3255 self.assertEqual(utext, el.text) 3256 3257 def test_deepcopy_elementtree(self): 3258 Element = self.etree.Element 3259 ElementTree = self.etree.ElementTree 3260 3261 a = Element('a') 3262 a.text = "Foo" 3263 atree = ElementTree(a) 3264 3265 btree = copy.deepcopy(atree) 3266 self.assertEqual("Foo", atree.getroot().text) 3267 self.assertEqual("Foo", btree.getroot().text) 3268 self.assertFalse(btree is atree) 3269 self.assertFalse(btree.getroot() is atree.getroot()) 3270 3271 def test_deepcopy(self): 3272 Element = self.etree.Element 3273 3274 a = Element('a') 3275 a.text = 'Foo' 3276 3277 b = copy.deepcopy(a) 3278 self.assertEqual('Foo', b.text) 3279 3280 b.text = 'Bar' 3281 self.assertEqual('Bar', b.text) 3282 self.assertEqual('Foo', a.text) 3283 3284 del a 3285 self.assertEqual('Bar', b.text) 3286 3287 def test_deepcopy_tail(self): 3288 Element = self.etree.Element 3289 3290 a = Element('a') 3291 a.tail = 'Foo' 3292 3293 b = copy.deepcopy(a) 3294 self.assertEqual('Foo', b.tail) 3295 3296 b.tail = 'Bar' 3297 self.assertEqual('Bar', b.tail) 3298 self.assertEqual('Foo', a.tail) 3299 3300 del a 3301 self.assertEqual('Bar', b.tail) 3302 3303 def test_deepcopy_subelement(self): 3304 Element = self.etree.Element 3305 SubElement = self.etree.SubElement 3306 3307 root = Element('root') 3308 a = SubElement(root, 'a') 3309 a.text = 'FooText' 3310 a.tail = 'FooTail' 3311 3312 b = copy.deepcopy(a) 3313 self.assertEqual('FooText', b.text) 3314 self.assertEqual('FooTail', b.tail) 3315 3316 b.text = 'BarText' 3317 b.tail = 'BarTail' 3318 self.assertEqual('BarTail', b.tail) 3319 self.assertEqual('FooTail', a.tail) 3320 self.assertEqual('BarText', b.text) 3321 self.assertEqual('FooText', a.text) 3322 3323 del a 3324 self.assertEqual('BarTail', b.tail) 3325 self.assertEqual('BarText', b.text) 3326 3327 def test_deepcopy_namespaces(self): 3328 root = self.etree.XML(_bytes('''<doc xmlns="dns" xmlns:t="tns"> 3329 <parent><node t:foo="bar" /></parent> 3330 </doc>''')) 3331 self.assertEqual( 3332 root[0][0].get('{tns}foo'), 3333 copy.deepcopy(root[0])[0].get('{tns}foo') ) 3334 self.assertEqual( 3335 root[0][0].get('{tns}foo'), 3336 copy.deepcopy(root[0][0]).get('{tns}foo') ) 3337 3338 def test_deepcopy_append(self): 3339 # previously caused a crash 3340 Element = self.etree.Element 3341 tostring = self.etree.tostring 3342 3343 a = Element('a') 3344 b = copy.deepcopy(a) 3345 a.append( Element('C') ) 3346 b.append( Element('X') ) 3347 3348 self.assertEqual(_bytes('<a><C/></a>'), 3349 tostring(a).replace(_bytes(' '), _bytes(''))) 3350 self.assertEqual(_bytes('<a><X/></a>'), 3351 tostring(b).replace(_bytes(' '), _bytes(''))) 3352 3353 def test_deepcopy_comment(self): 3354 # previously caused a crash 3355 # not supported by ET < 1.3! 3356 Comment = self.etree.Comment 3357 3358 a = Comment("ONE") 3359 b = copy.deepcopy(a) 3360 b.text = "ANOTHER" 3361 3362 self.assertEqual('ONE', a.text) 3363 self.assertEqual('ANOTHER', b.text) 3364 3365 def test_shallowcopy(self): 3366 Element = self.etree.Element 3367 3368 a = Element('a') 3369 a.text = 'Foo' 3370 3371 b = copy.copy(a) 3372 self.assertEqual('Foo', b.text) 3373 3374 b.text = 'Bar' 3375 self.assertEqual('Bar', b.text) 3376 self.assertEqual('Foo', a.text) 3377 # XXX ElementTree will share nodes, but lxml.etree won't.. 3378 3379 def test_shallowcopy_elementtree(self): 3380 Element = self.etree.Element 3381 ElementTree = self.etree.ElementTree 3382 3383 a = Element('a') 3384 a.text = 'Foo' 3385 atree = ElementTree(a) 3386 3387 btree = copy.copy(atree) 3388 self.assertFalse(btree is atree) 3389 self.assertTrue(btree.getroot() is atree.getroot()) 3390 self.assertEqual('Foo', atree.getroot().text) 3391 3392 def _test_element_boolean(self): 3393 # deprecated as of ET 1.3/lxml 2.0 3394 etree = self.etree 3395 e = etree.Element('foo') 3396 self.assertEqual(False, bool(e)) 3397 etree.SubElement(e, 'bar') 3398 self.assertEqual(True, bool(e)) 3399 e = etree.Element('foo') 3400 e.text = 'hey' 3401 self.assertEqual(False, bool(e)) 3402 e = etree.Element('foo') 3403 e.tail = 'bar' 3404 self.assertEqual(False, bool(e)) 3405 e = etree.Element('foo') 3406 e.set('bar', 'Bar') 3407 self.assertEqual(False, bool(e)) 3408 3409 def test_multiple_elementrees(self): 3410 etree = self.etree 3411 3412 a = etree.Element('a') 3413 b = etree.SubElement(a, 'b') 3414 3415 t = etree.ElementTree(a) 3416 self.assertEqual(self._rootstring(t), _bytes('<a><b/></a>')) 3417 3418 t1 = etree.ElementTree(a) 3419 self.assertEqual(self._rootstring(t1), _bytes('<a><b/></a>')) 3420 self.assertEqual(self._rootstring(t), _bytes('<a><b/></a>')) 3421 3422 t2 = etree.ElementTree(b) 3423 self.assertEqual(self._rootstring(t2), _bytes('<b/>')) 3424 self.assertEqual(self._rootstring(t1), _bytes('<a><b/></a>')) 3425 self.assertEqual(self._rootstring(t), _bytes('<a><b/></a>')) 3426 3427 def test_qname(self): 3428 etree = self.etree 3429 qname = etree.QName('myns', 'a') 3430 a1 = etree.Element(qname) 3431 a2 = etree.SubElement(a1, qname) 3432 self.assertEqual(a1.tag, "{myns}a") 3433 self.assertEqual(a2.tag, "{myns}a") 3434 3435 def test_qname_cmp(self): 3436 etree = self.etree 3437 qname1 = etree.QName('myns', 'a') 3438 qname2 = etree.QName('myns', 'a') 3439 self.assertEqual(qname1, "{myns}a") 3440 self.assertEqual("{myns}a", qname2) 3441 self.assertEqual(qname1, qname1) 3442 self.assertEqual(qname1, qname2) 3443 3444 def test_qname_attribute_getset(self): 3445 etree = self.etree 3446 qname = etree.QName('myns', 'a') 3447 3448 a = etree.Element(qname) 3449 a.set(qname, "value") 3450 3451 self.assertEqual(a.get(qname), "value") 3452 self.assertEqual(a.get("{myns}a"), "value") 3453 3454 def test_qname_attrib(self): 3455 etree = self.etree 3456 qname = etree.QName('myns', 'a') 3457 3458 a = etree.Element(qname) 3459 a.attrib[qname] = "value" 3460 3461 self.assertEqual(a.attrib[qname], "value") 3462 self.assertEqual(a.attrib.get(qname), "value") 3463 3464 self.assertEqual(a.attrib["{myns}a"], "value") 3465 self.assertEqual(a.attrib.get("{myns}a"), "value") 3466 3467 def test_qname_attribute_resolve(self): 3468 etree = self.etree 3469 qname = etree.QName('http://myns', 'a') 3470 a = etree.Element(qname) 3471 a.set(qname, qname) 3472 3473 self.assertXML( 3474 _bytes('<ns0:a xmlns:ns0="http://myns" ns0:a="ns0:a"></ns0:a>'), 3475 a) 3476 3477 def test_qname_attribute_resolve_new(self): 3478 etree = self.etree 3479 qname = etree.QName('http://myns', 'a') 3480 a = etree.Element('a') 3481 a.set('a', qname) 3482 3483 self.assertXML( 3484 _bytes('<a xmlns:ns0="http://myns" a="ns0:a"></a>'), 3485 a) 3486 3487 def test_qname_attrib_resolve(self): 3488 etree = self.etree 3489 qname = etree.QName('http://myns', 'a') 3490 a = etree.Element(qname) 3491 a.attrib[qname] = qname 3492 3493 self.assertXML( 3494 _bytes('<ns0:a xmlns:ns0="http://myns" ns0:a="ns0:a"></ns0:a>'), 3495 a) 3496 3497 def test_parser_version(self): 3498 etree = self.etree 3499 parser = etree.XMLParser() 3500 if hasattr(parser, "version"): 3501 # ElementTree 1.3+, cET 3502 self.assertTrue(re.match("[^ ]+ [0-9.]+", parser.version)) 3503 3504 # feed parser interface 3505 3506 def test_feed_parser_bytes(self): 3507 parser = self.XMLParser() 3508 3509 parser.feed(_bytes('<?xml version=')) 3510 parser.feed(_bytes('"1.0"?><ro')) 3511 parser.feed(_bytes('ot><')) 3512 parser.feed(_bytes('a test="works"/')) 3513 parser.feed(_bytes('></root')) 3514 parser.feed(_bytes('>')) 3515 3516 root = parser.close() 3517 3518 self.assertEqual(root.tag, "root") 3519 self.assertEqual(root[0].tag, "a") 3520 self.assertEqual(root[0].get("test"), "works") 3521 3522 def test_feed_parser_unicode_ascii(self): 3523 parser = self.XMLParser() 3524 3525 parser.feed(_bytes(u'<?xml version=')) 3526 parser.feed(_bytes(u'"1.0"?><ro')) 3527 parser.feed(_bytes(u'ot><')) 3528 parser.feed(_bytes(u'a test="works"/')) 3529 parser.feed(_bytes(u'></root')) 3530 parser.feed(_bytes(u'>')) 3531 3532 root = parser.close() 3533 3534 self.assertEqual(root.tag, "root") 3535 self.assertEqual(root[0].tag, "a") 3536 self.assertEqual(root[0].get("test"), "works") 3537 3538 @et_needs_pyversion(3) 3539 def test_feed_parser_unicode_astral(self): 3540 parser = self.XMLParser() 3541 3542 astral_chunk = u'-- \U00010143 --' # astral (4 bytes/chr) 3543 latin1_chunk = u'-- \xf8 --' # Latin1 (1 byte/chr) 3544 3545 parser.feed(u'<ro') # ASCII (1 byte/chr) 3546 parser.feed(u'ot><') 3547 parser.feed(u'a test="w\N{DIAMETER SIGN}rks">') # BMP (2 bytes/chr) 3548 parser.feed(astral_chunk) 3549 parser.feed(latin1_chunk) 3550 parser.feed(u'</a></root') 3551 parser.feed(u'>') 3552 3553 root = parser.close() 3554 3555 self.assertEqual(root.tag, "root") 3556 self.assertEqual(root[0].tag, "a") 3557 self.assertEqual(root[0].get("test"), u"w\N{DIAMETER SIGN}rks") 3558 self.assertEqual(root[0].text, astral_chunk + latin1_chunk) 3559 3560 @et_needs_pyversion(3) 3561 def test_feed_parser_unicode_astral_large(self): 3562 parser = self.XMLParser() 3563 3564 astral_chunk = u'-- \U00010143 --' * (2 ** 16) # astral (4 bytes/chr) 3565 latin1_chunk = u'-- \xf8 --' # Latin1 (1 byte/chr) 3566 3567 parser.feed(u'<ro') 3568 parser.feed(u'ot><') # ASCII (1 byte/chr) 3569 parser.feed(u'a test="w\N{DIAMETER SIGN}rks">') # BMP (2 bytes/chr) 3570 parser.feed(astral_chunk) 3571 parser.feed((astral_chunk + u"</a> <a>" + astral_chunk) * 16) 3572 parser.feed(latin1_chunk) 3573 parser.feed(u'</a></root') 3574 parser.feed(u'>') 3575 3576 root = parser.close() 3577 3578 self.assertEqual(root.tag, "root") 3579 self.assertEqual(root[0].get("test"), u"w\N{DIAMETER SIGN}rks") 3580 for child in root[:-1]: 3581 self.assertEqual(child.tag, "a") 3582 self.assertEqual(child.text, astral_chunk * 2) 3583 self.assertEqual(root[-1].tag, "a") 3584 self.assertEqual(root[-1].text, astral_chunk + latin1_chunk) 3585 3586 required_versions_ET['test_feed_parser_error_close_empty'] = (1,3) 3587 def test_feed_parser_error_close_empty(self): 3588 ParseError = self.etree.ParseError 3589 parser = self.XMLParser() 3590 self.assertRaises(ParseError, parser.close) 3591 3592 required_versions_ET['test_feed_parser_error_close_incomplete'] = (1,3) 3593 def test_feed_parser_error_close_incomplete(self): 3594 ParseError = self.etree.ParseError 3595 parser = self.XMLParser() 3596 3597 parser.feed('<?xml version=') 3598 parser.feed('"1.0"?><ro') 3599 3600 self.assertRaises(ParseError, parser.close) 3601 3602 required_versions_ET['test_feed_parser_error_broken'] = (1,3) 3603 def test_feed_parser_error_broken(self): 3604 ParseError = self.etree.ParseError 3605 parser = self.XMLParser() 3606 3607 parser.feed('<?xml version=') 3608 parser.feed('"1.0"?><ro') 3609 try: 3610 parser.feed('<><><><><><><') 3611 except ParseError: 3612 # can raise, but not required before close() 3613 pass 3614 3615 self.assertRaises(ParseError, parser.close) 3616 3617 required_versions_ET['test_feed_parser_error_position'] = (1,3) 3618 def test_feed_parser_error_position(self): 3619 ParseError = self.etree.ParseError 3620 parser = self.XMLParser() 3621 try: 3622 parser.close() 3623 except ParseError: 3624 e = sys.exc_info()[1] 3625 self.assertNotEqual(None, e.code) 3626 self.assertNotEqual(0, e.code) 3627 self.assertTrue(isinstance(e.position, tuple)) 3628 self.assertTrue(e.position >= (0, 0)) 3629 3630 # parser target interface 3631 3632 required_versions_ET['test_parser_target_property'] = (1,3) 3633 def test_parser_target_property(self): 3634 class Target(object): 3635 pass 3636 3637 target = Target() 3638 parser = self.XMLParser(target=target) 3639 3640 self.assertEqual(target, parser.target) 3641 3642 def test_parser_target_tag(self): 3643 assertEqual = self.assertEqual 3644 assertFalse = self.assertFalse 3645 3646 events = [] 3647 class Target(object): 3648 def start(self, tag, attrib): 3649 events.append("start") 3650 assertFalse(attrib) 3651 assertEqual("TAG", tag) 3652 def end(self, tag): 3653 events.append("end") 3654 assertEqual("TAG", tag) 3655 def close(self): 3656 return "DONE" 3657 3658 parser = self.XMLParser(target=Target()) 3659 3660 parser.feed("<TAG/>") 3661 done = parser.close() 3662 3663 self.assertEqual("DONE", done) 3664 self.assertEqual(["start", "end"], events) 3665 3666 def test_parser_target_error_in_start(self): 3667 assertEqual = self.assertEqual 3668 3669 events = [] 3670 class Target(object): 3671 def start(self, tag, attrib): 3672 events.append("start") 3673 assertEqual("TAG", tag) 3674 raise ValueError("TEST") 3675 def end(self, tag): 3676 events.append("end") 3677 assertEqual("TAG", tag) 3678 def close(self): 3679 return "DONE" 3680 3681 parser = self.XMLParser(target=Target()) 3682 3683 try: 3684 parser.feed("<TAG/>") 3685 except ValueError: 3686 self.assertTrue('TEST' in str(sys.exc_info()[1])) 3687 else: 3688 self.assertTrue(False) 3689 if 'lxml' in self.etree.__name__: 3690 self.assertEqual(["start"], events) 3691 else: 3692 # cElementTree calls end() as well 3693 self.assertTrue("start" in events) 3694 3695 def test_parser_target_error_in_end(self): 3696 assertEqual = self.assertEqual 3697 3698 events = [] 3699 class Target(object): 3700 def start(self, tag, attrib): 3701 events.append("start") 3702 assertEqual("TAG", tag) 3703 def end(self, tag): 3704 events.append("end") 3705 assertEqual("TAG", tag) 3706 raise ValueError("TEST") 3707 def close(self): 3708 return "DONE" 3709 3710 parser = self.XMLParser(target=Target()) 3711 3712 try: 3713 parser.feed("<TAG/>") 3714 except ValueError: 3715 self.assertTrue('TEST' in str(sys.exc_info()[1])) 3716 else: 3717 self.assertTrue(False) 3718 self.assertEqual(["start", "end"], events) 3719 3720 def test_parser_target_error_in_close(self): 3721 assertEqual = self.assertEqual 3722 3723 events = [] 3724 class Target(object): 3725 def start(self, tag, attrib): 3726 events.append("start") 3727 assertEqual("TAG", tag) 3728 def end(self, tag): 3729 events.append("end") 3730 assertEqual("TAG", tag) 3731 def close(self): 3732 raise ValueError("TEST") 3733 3734 parser = self.XMLParser(target=Target()) 3735 3736 try: 3737 parser.feed("<TAG/>") 3738 parser.close() 3739 except ValueError: 3740 self.assertTrue('TEST' in str(sys.exc_info()[1])) 3741 else: 3742 self.assertTrue(False) 3743 self.assertEqual(["start", "end"], events) 3744 3745 def test_parser_target_error_in_start_and_close(self): 3746 assertEqual = self.assertEqual 3747 3748 events = [] 3749 class Target(object): 3750 def start(self, tag, attrib): 3751 events.append("start") 3752 assertEqual("TAG", tag) 3753 raise IndexError("TEST-IE") 3754 def end(self, tag): 3755 events.append("end") 3756 assertEqual("TAG", tag) 3757 def close(self): 3758 raise ValueError("TEST-VE") 3759 3760 parser = self.XMLParser(target=Target()) 3761 3762 try: 3763 parser.feed("<TAG/>") 3764 parser.close() 3765 except IndexError: 3766 if 'lxml' in self.etree.__name__: 3767 # we try not to swallow the initial exception in Py2 3768 self.assertTrue(sys.version_info[0] < 3) 3769 self.assertTrue('TEST-IE' in str(sys.exc_info()[1])) 3770 except ValueError: 3771 if 'lxml' in self.etree.__name__: 3772 self.assertTrue(sys.version_info[0] >= 3) 3773 self.assertTrue('TEST-VE' in str(sys.exc_info()[1])) 3774 else: 3775 self.assertTrue(False) 3776 3777 if 'lxml' in self.etree.__name__: 3778 self.assertEqual(["start"], events) 3779 else: 3780 # cElementTree calls end() as well 3781 self.assertTrue("start" in events) 3782 3783 def test_elementtree_parser_target(self): 3784 assertEqual = self.assertEqual 3785 assertFalse = self.assertFalse 3786 Element = self.etree.Element 3787 3788 events = [] 3789 class Target(object): 3790 def start(self, tag, attrib): 3791 events.append("start") 3792 assertFalse(attrib) 3793 assertEqual("TAG", tag) 3794 def end(self, tag): 3795 events.append("end") 3796 assertEqual("TAG", tag) 3797 def close(self): 3798 return Element("DONE") 3799 3800 parser = self.XMLParser(target=Target()) 3801 tree = self.etree.ElementTree() 3802 tree.parse(BytesIO("<TAG/>"), parser=parser) 3803 3804 self.assertEqual("DONE", tree.getroot().tag) 3805 self.assertEqual(["start", "end"], events) 3806 3807 def test_parser_target_attrib(self): 3808 assertEqual = self.assertEqual 3809 3810 events = [] 3811 class Target(object): 3812 def start(self, tag, attrib): 3813 events.append("start-" + tag) 3814 for name, value in attrib.items(): 3815 assertEqual(tag + name, value) 3816 def end(self, tag): 3817 events.append("end-" + tag) 3818 def close(self): 3819 return "DONE" 3820 3821 parser = self.XMLParser(target=Target()) 3822 3823 parser.feed('<root a="roota" b="rootb"><sub c="subc"/></root>') 3824 done = parser.close() 3825 3826 self.assertEqual("DONE", done) 3827 self.assertEqual(["start-root", "start-sub", "end-sub", "end-root"], 3828 events) 3829 3830 def test_parser_target_data(self): 3831 events = [] 3832 class Target(object): 3833 def start(self, tag, attrib): 3834 events.append("start-" + tag) 3835 def end(self, tag): 3836 events.append("end-" + tag) 3837 def data(self, data): 3838 events.append("data-" + data) 3839 def close(self): 3840 return "DONE" 3841 3842 parser = self.XMLParser(target=Target()) 3843 3844 parser.feed('<root>A<sub/>B</root>') 3845 done = parser.close() 3846 3847 self.assertEqual("DONE", done) 3848 self.assertEqual(["start-root", "data-A", "start-sub", 3849 "end-sub", "data-B", "end-root"], 3850 events) 3851 3852 def test_parser_target_entity(self): 3853 events = [] 3854 class Target(object): 3855 def __init__(self): 3856 self._data = [] 3857 def _flush_data(self): 3858 if self._data: 3859 events.append("data-" + ''.join(self._data)) 3860 del self._data[:] 3861 def start(self, tag, attrib): 3862 self._flush_data() 3863 events.append("start-" + tag) 3864 def end(self, tag): 3865 self._flush_data() 3866 events.append("end-" + tag) 3867 def data(self, data): 3868 self._data.append(data) 3869 def close(self): 3870 self._flush_data() 3871 return "DONE" 3872 3873 parser = self.XMLParser(target=Target()) 3874 3875 dtd = ''' 3876 <!DOCTYPE root [ 3877 <!ELEMENT root (sub*)> 3878 <!ELEMENT sub (#PCDATA)> 3879 <!ENTITY ent "an entity"> 3880 ]> 3881 ''' 3882 parser.feed(dtd+'<root><sub/><sub>this is &ent;</sub><sub/></root>') 3883 done = parser.close() 3884 3885 self.assertEqual("DONE", done) 3886 self.assertEqual(["start-root", "start-sub", "end-sub", "start-sub", 3887 "data-this is an entity", 3888 "end-sub", "start-sub", "end-sub", "end-root"], 3889 events) 3890 3891 required_versions_ET['test_parser_target_entity_unknown'] = (1,3) 3892 def test_parser_target_entity_unknown(self): 3893 events = [] 3894 class Target(object): 3895 def __init__(self): 3896 self._data = [] 3897 def _flush_data(self): 3898 if self._data: 3899 events.append("data-" + ''.join(self._data)) 3900 del self._data[:] 3901 def start(self, tag, attrib): 3902 self._flush_data() 3903 events.append("start-" + tag) 3904 def end(self, tag): 3905 self._flush_data() 3906 events.append("end-" + tag) 3907 def data(self, data): 3908 self._data.append(data) 3909 def close(self): 3910 self._flush_data() 3911 return "DONE" 3912 3913 parser = self.XMLParser(target=Target()) 3914 3915 def feed(): 3916 parser.feed('<root><sub/><sub>some &ent;</sub><sub/></root>') 3917 parser.close() 3918 3919 self.assertRaises(self.etree.ParseError, feed) 3920 3921 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 3922 def test_parser_target_start_end_ns(self): 3923 class Builder(list): 3924 def start(self, tag, attrib): 3925 self.append(("start", tag)) 3926 def end(self, tag): 3927 self.append(("end", tag)) 3928 def data(self, text): 3929 pass 3930 def pi(self, target, data): 3931 self.append(("pi", target, data)) 3932 def comment(self, data): 3933 self.append(("comment", data)) 3934 def start_ns(self, prefix, uri): 3935 self.append(("start-ns", prefix, uri)) 3936 def end_ns(self, prefix): 3937 self.append(("end-ns", prefix)) 3938 3939 builder = Builder() 3940 parser = self.etree.XMLParser(target=builder) 3941 parser.feed(textwrap.dedent("""\ 3942 <?pi data?> 3943 <!-- comment --> 3944 <root xmlns='namespace'> 3945 <element key='value'>text</element> 3946 <element>text</element>tail 3947 <empty-element/> 3948 </root> 3949 """)) 3950 self.assertEqual(builder, [ 3951 ('pi', 'pi', 'data'), 3952 ('comment', ' comment '), 3953 ('start-ns', '', 'namespace'), 3954 ('start', '{namespace}root'), 3955 ('start', '{namespace}element'), 3956 ('end', '{namespace}element'), 3957 ('start', '{namespace}element'), 3958 ('end', '{namespace}element'), 3959 ('start', '{namespace}empty-element'), 3960 ('end', '{namespace}empty-element'), 3961 ('end', '{namespace}root'), 3962 ('end-ns', ''), 3963 ]) 3964 3965 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 3966 def test_parser_target_end_ns(self): 3967 class Builder(list): 3968 def end_ns(self, prefix): 3969 self.append(("end-ns", prefix)) 3970 3971 builder = Builder() 3972 parser = self.etree.XMLParser(target=builder) 3973 parser.feed(textwrap.dedent("""\ 3974 <?pi data?> 3975 <!-- comment --> 3976 <root xmlns='namespace' xmlns:p='pns'> 3977 <element key='value'>text</element> 3978 <p:element>text</p:element>tail 3979 <empty-element/> 3980 </root> 3981 """)) 3982 self.assertEqual(builder, [ 3983 ('end-ns', 'p'), 3984 ('end-ns', ''), 3985 ]) 3986 3987 def test_treebuilder(self): 3988 builder = self.etree.TreeBuilder() 3989 el = builder.start("root", {'a':'A', 'b':'B'}) 3990 self.assertEqual("root", el.tag) 3991 self.assertEqual({'a':'A', 'b':'B'}, el.attrib) 3992 builder.data("ROOTTEXT") 3993 el = builder.start("child", {'x':'X', 'y':'Y'}) 3994 self.assertEqual("child", el.tag) 3995 self.assertEqual({'x':'X', 'y':'Y'}, el.attrib) 3996 builder.data("CHILDTEXT") 3997 el = builder.end("child") 3998 self.assertEqual("child", el.tag) 3999 self.assertEqual({'x':'X', 'y':'Y'}, el.attrib) 4000 self.assertEqual("CHILDTEXT", el.text) 4001 self.assertEqual(None, el.tail) 4002 builder.data("CHILDTAIL") 4003 root = builder.end("root") 4004 4005 self.assertEqual("root", root.tag) 4006 self.assertEqual("ROOTTEXT", root.text) 4007 self.assertEqual("CHILDTEXT", root[0].text) 4008 self.assertEqual("CHILDTAIL", root[0].tail) 4009 4010 def test_treebuilder_target(self): 4011 parser = self.XMLParser(target=self.etree.TreeBuilder()) 4012 parser.feed('<root>ROOTTEXT<child>CHILDTEXT</child>CHILDTAIL</root>') 4013 root = parser.close() 4014 4015 self.assertEqual("root", root.tag) 4016 self.assertEqual("ROOTTEXT", root.text) 4017 self.assertEqual("CHILDTEXT", root[0].text) 4018 self.assertEqual("CHILDTAIL", root[0].tail) 4019 4020 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 4021 def test_treebuilder_comment(self): 4022 ET = self.etree 4023 b = ET.TreeBuilder() 4024 self.assertEqual(b.comment('ctext').tag, ET.Comment) 4025 self.assertEqual(b.comment('ctext').text, 'ctext') 4026 4027 b = ET.TreeBuilder(comment_factory=ET.Comment) 4028 self.assertEqual(b.comment('ctext').tag, ET.Comment) 4029 self.assertEqual(b.comment('ctext').text, 'ctext') 4030 4031 #b = ET.TreeBuilder(comment_factory=len) 4032 #self.assertEqual(b.comment('ctext'), len('ctext')) 4033 4034 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 4035 def test_treebuilder_pi(self): 4036 ET = self.etree 4037 is_lxml = ET.__name__ == 'lxml.etree' 4038 4039 b = ET.TreeBuilder() 4040 self.assertEqual(b.pi('target', None).tag, ET.PI) 4041 if is_lxml: 4042 self.assertEqual(b.pi('target', None).target, 'target') 4043 else: 4044 self.assertEqual(b.pi('target', None).text, 'target') 4045 4046 b = ET.TreeBuilder(pi_factory=ET.PI) 4047 self.assertEqual(b.pi('target').tag, ET.PI) 4048 if is_lxml: 4049 self.assertEqual(b.pi('target').target, "target") 4050 else: 4051 self.assertEqual(b.pi('target').text, "target") 4052 self.assertEqual(b.pi('pitarget', ' text ').tag, ET.PI) 4053 if is_lxml: 4054 self.assertEqual(b.pi('pitarget', ' text ').target, "pitarget") 4055 self.assertEqual(b.pi('pitarget', ' text ').text, " text ") 4056 else: 4057 self.assertEqual(b.pi('pitarget', ' text ').text, "pitarget text ") 4058 4059 #b = ET.TreeBuilder(pi_factory=lambda target, text: (len(target), text)) 4060 #self.assertEqual(b.pi('target'), (len('target'), None)) 4061 #self.assertEqual(b.pi('pitarget', ' text '), (len('pitarget'), ' text ')) 4062 4063 def test_late_tail(self): 4064 # Issue #37399: The tail of an ignored comment could overwrite the text before it. 4065 ET = self.etree 4066 class TreeBuilderSubclass(ET.TreeBuilder): 4067 pass 4068 4069 if ET.__name__ == 'lxml.etree': 4070 def assert_content(a): 4071 self.assertEqual(a.text, "text") 4072 self.assertEqual(a[0].tail, "tail") 4073 else: 4074 def assert_content(a): 4075 self.assertEqual(a.text, "texttail") 4076 4077 xml = "<a>text<!-- comment -->tail</a>" 4078 a = ET.fromstring(xml) 4079 assert_content(a) 4080 4081 parser = ET.XMLParser(target=TreeBuilderSubclass()) 4082 parser.feed(xml) 4083 a = parser.close() 4084 assert_content(a) 4085 4086 xml = "<a>text<?pi data?>tail</a>" 4087 a = ET.fromstring(xml) 4088 assert_content(a) 4089 4090 xml = "<a>text<?pi data?>tail</a>" 4091 parser = ET.XMLParser(target=TreeBuilderSubclass()) 4092 parser.feed(xml) 4093 a = parser.close() 4094 assert_content(a) 4095 4096 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 4097 def test_late_tail_mix_pi_comments(self): 4098 # Issue #37399: The tail of an ignored comment could overwrite the text before it. 4099 # Test appending tails to comments/pis. 4100 ET = self.etree 4101 class TreeBuilderSubclass(ET.TreeBuilder): 4102 pass 4103 4104 xml = "<a>text<?pi1?> <!-- comment -->\n<?pi2?>tail</a>" 4105 parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True, insert_pis=False)) 4106 parser.feed(xml) 4107 a = parser.close() 4108 self.assertEqual(a[0].text, ' comment ') 4109 self.assertEqual(a[0].tail, '\ntail') 4110 self.assertEqual(a.text, "text ") 4111 4112 parser = ET.XMLParser(target=TreeBuilderSubclass(insert_comments=True, insert_pis=False)) 4113 parser.feed(xml) 4114 a = parser.close() 4115 self.assertEqual(a[0].text, ' comment ') 4116 self.assertEqual(a[0].tail, '\ntail') 4117 self.assertEqual(a.text, "text ") 4118 4119 xml = "<a>text<!-- comment -->\n<?pi data?>tail</a>" 4120 parser = ET.XMLParser(target=ET.TreeBuilder(insert_pis=True, insert_comments=False)) 4121 parser.feed(xml) 4122 a = parser.close() 4123 self.assertEqual(a[0].text[-4:], 'data') 4124 self.assertEqual(a[0].tail, 'tail') 4125 self.assertEqual(a.text, "text\n") 4126 4127 parser = ET.XMLParser(target=TreeBuilderSubclass(insert_pis=True, insert_comments=False)) 4128 parser.feed(xml) 4129 a = parser.close() 4130 self.assertEqual(a[0].text[-4:], 'data') 4131 self.assertEqual(a[0].tail, 'tail') 4132 self.assertEqual(a.text, "text\n") 4133 4134 # helper methods 4135 4136 def _writeElement(self, element, encoding='us-ascii'): 4137 """Write out element for comparison. 4138 """ 4139 data = self.etree.tostring(element, encoding=encoding) 4140 return canonicalize(data) 4141 4142 def _writeElementFile(self, element, encoding='us-ascii'): 4143 """Write out element for comparison, using real file. 4144 """ 4145 ElementTree = self.etree.ElementTree 4146 with tmpfile() as filename: 4147 with open(filename, 'wb') as f: 4148 tree = ElementTree(element=element) 4149 tree.write(f, encoding=encoding) 4150 with open(filename, 'rb') as f: 4151 data = f.read() 4152 return canonicalize(data) 4153 4154 def assertXML(self, expected, element, encoding='us-ascii'): 4155 """Writes element out and checks whether it is expected. 4156 4157 Does this two ways; once using BytesIO, once using a real file. 4158 """ 4159 if isinstance(expected, unicode): 4160 expected = expected.encode(encoding) 4161 self.assertEqual(expected, self._writeElement(element, encoding)) 4162 self.assertEqual(expected, self._writeElementFile(element, encoding)) 4163 4164 def assertEncodingDeclaration(self, result, encoding): 4165 "Checks if the result XML byte string specifies the encoding." 4166 enc_re = r"<\?xml[^>]+ encoding=[\"']([^\"']+)[\"']" 4167 if isinstance(result, str): 4168 has_encoding = re.compile(enc_re).match 4169 else: 4170 has_encoding = re.compile(_bytes(enc_re)).match 4171 self.assertTrue(has_encoding(result)) 4172 result_encoding = has_encoding(result).group(1) 4173 self.assertEqual(result_encoding.upper(), encoding.upper()) 4174 4175 def _rootstring(self, tree): 4176 return self.etree.tostring(tree.getroot()).replace( 4177 _bytes(' '), _bytes('')).replace(_bytes('\n'), _bytes('')) 4178 4179 def _check_element_tree(self, tree): 4180 self._check_element(tree.getroot()) 4181 4182 def _check_element(self, element): 4183 self.assertTrue(hasattr(element, 'tag')) 4184 self.assertTrue(hasattr(element, 'attrib')) 4185 self.assertTrue(hasattr(element, 'text')) 4186 self.assertTrue(hasattr(element, 'tail')) 4187 self._check_string(element.tag) 4188 self._check_mapping(element.attrib) 4189 if element.text is not None: 4190 self._check_string(element.text) 4191 if element.tail is not None: 4192 self._check_string(element.tail) 4193 4194 def _check_string(self, string): 4195 len(string) 4196 for char in string: 4197 self.assertEqual(1, len(char)) 4198 new_string = string + "" 4199 new_string = string + " " 4200 string[:0] 4201 4202 def _check_mapping(self, mapping): 4203 len(mapping) 4204 keys = mapping.keys() 4205 values = mapping.values() 4206 items = mapping.items() 4207 for key in keys: 4208 item = mapping[key] 4209 mapping["key"] = "value" 4210 self.assertEqual("value", mapping["key"]) 4211 4212 4213class _ElementSlicingTest(unittest.TestCase): 4214 etree = None 4215 4216 def _elem_tags(self, elemlist): 4217 return [e.tag for e in elemlist] 4218 4219 def _subelem_tags(self, elem): 4220 return self._elem_tags(list(elem)) 4221 4222 def _make_elem_with_children(self, numchildren): 4223 """Create an Element with a tag 'a', with the given amount of children 4224 named 'a0', 'a1' ... and so on. 4225 4226 """ 4227 e = self.etree.Element('a') 4228 for i in range(numchildren): 4229 self.etree.SubElement(e, 'a%s' % i) 4230 return e 4231 4232 def test_getslice_single_index(self): 4233 e = self._make_elem_with_children(10) 4234 4235 self.assertEqual(e[1].tag, 'a1') 4236 self.assertEqual(e[-2].tag, 'a8') 4237 4238 self.assertRaises(IndexError, lambda: e[12]) 4239 self.assertRaises(IndexError, lambda: e[-12]) 4240 4241 def test_getslice_range(self): 4242 e = self._make_elem_with_children(6) 4243 4244 self.assertEqual(self._elem_tags(e[3:]), ['a3', 'a4', 'a5']) 4245 self.assertEqual(self._elem_tags(e[3:6]), ['a3', 'a4', 'a5']) 4246 self.assertEqual(self._elem_tags(e[3:16]), ['a3', 'a4', 'a5']) 4247 self.assertEqual(self._elem_tags(e[3:5]), ['a3', 'a4']) 4248 self.assertEqual(self._elem_tags(e[3:-1]), ['a3', 'a4']) 4249 self.assertEqual(self._elem_tags(e[:2]), ['a0', 'a1']) 4250 4251 def test_getslice_steps(self): 4252 e = self._make_elem_with_children(10) 4253 4254 self.assertEqual(self._elem_tags(e[8:10:1]), ['a8', 'a9']) 4255 self.assertEqual(self._elem_tags(e[::3]), ['a0', 'a3', 'a6', 'a9']) 4256 self.assertEqual(self._elem_tags(e[::8]), ['a0', 'a8']) 4257 self.assertEqual(self._elem_tags(e[1::8]), ['a1', 'a9']) 4258 self.assertEqual(self._elem_tags(e[3::sys.maxsize]), ['a3']) 4259 self.assertEqual(self._elem_tags(e[3::sys.maxsize<<64]), ['a3']) 4260 4261 def test_getslice_negative_steps(self): 4262 e = self._make_elem_with_children(4) 4263 4264 self.assertEqual(self._elem_tags(e[::-1]), ['a3', 'a2', 'a1', 'a0']) 4265 self.assertEqual(self._elem_tags(e[::-2]), ['a3', 'a1']) 4266 self.assertEqual(self._elem_tags(e[3::-sys.maxsize]), ['a3']) 4267 self.assertEqual(self._elem_tags(e[3::-sys.maxsize-1]), ['a3']) 4268 self.assertEqual(self._elem_tags(e[3::-sys.maxsize<<64]), ['a3']) 4269 4270 def test_delslice(self): 4271 e = self._make_elem_with_children(4) 4272 del e[0:2] 4273 self.assertEqual(self._subelem_tags(e), ['a2', 'a3']) 4274 4275 e = self._make_elem_with_children(4) 4276 del e[0:] 4277 self.assertEqual(self._subelem_tags(e), []) 4278 4279 e = self._make_elem_with_children(4) 4280 del e[::-1] 4281 self.assertEqual(self._subelem_tags(e), []) 4282 4283 e = self._make_elem_with_children(4) 4284 del e[::-2] 4285 self.assertEqual(self._subelem_tags(e), ['a0', 'a2']) 4286 4287 e = self._make_elem_with_children(4) 4288 del e[1::2] 4289 self.assertEqual(self._subelem_tags(e), ['a0', 'a2']) 4290 4291 e = self._make_elem_with_children(2) 4292 del e[::2] 4293 self.assertEqual(self._subelem_tags(e), ['a1']) 4294 4295 def test_setslice_single_index(self): 4296 e = self._make_elem_with_children(4) 4297 e[1] = self.etree.Element('b') 4298 self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3']) 4299 4300 e[-2] = self.etree.Element('c') 4301 self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'c', 'a3']) 4302 4303 with self.assertRaises(IndexError): 4304 e[5] = self.etree.Element('d') 4305 with self.assertRaises(IndexError): 4306 e[-5] = self.etree.Element('d') 4307 self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'c', 'a3']) 4308 4309 def test_setslice_range(self): 4310 e = self._make_elem_with_children(4) 4311 e[1:3] = [self.etree.Element('b%s' % i) for i in range(2)] 4312 self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'b1', 'a3']) 4313 4314 e = self._make_elem_with_children(4) 4315 e[1:3] = [self.etree.Element('b')] 4316 self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a3']) 4317 4318 e = self._make_elem_with_children(4) 4319 e[1:3] = [self.etree.Element('b%s' % i) for i in range(3)] 4320 self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'b1', 'b2', 'a3']) 4321 4322 def test_setslice_steps(self): 4323 e = self._make_elem_with_children(6) 4324 e[1:5:2] = [self.etree.Element('b%s' % i) for i in range(2)] 4325 self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'a2', 'b1', 'a4', 'a5']) 4326 4327 e = self._make_elem_with_children(6) 4328 with self.assertRaises(ValueError): 4329 e[1:5:2] = [self.etree.Element('b')] 4330 with self.assertRaises(ValueError): 4331 e[1:5:2] = [self.etree.Element('b%s' % i) for i in range(3)] 4332 with self.assertRaises(ValueError): 4333 e[1:5:2] = [] 4334 self.assertEqual(self._subelem_tags(e), ['a0', 'a1', 'a2', 'a3', 'a4', 'a5']) 4335 4336 e = self._make_elem_with_children(4) 4337 e[1::sys.maxsize] = [self.etree.Element('b')] 4338 self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3']) 4339 e[1::sys.maxsize<<64] = [self.etree.Element('c')] 4340 self.assertEqual(self._subelem_tags(e), ['a0', 'c', 'a2', 'a3']) 4341 4342 def test_setslice_negative_steps(self): 4343 e = self._make_elem_with_children(4) 4344 e[2:0:-1] = [self.etree.Element('b%s' % i) for i in range(2)] 4345 self.assertEqual(self._subelem_tags(e), ['a0', 'b1', 'b0', 'a3']) 4346 4347 e = self._make_elem_with_children(4) 4348 with self.assertRaises(ValueError): 4349 e[2:0:-1] = [self.etree.Element('b')] 4350 with self.assertRaises(ValueError): 4351 e[2:0:-1] = [self.etree.Element('b%s' % i) for i in range(3)] 4352 with self.assertRaises(ValueError): 4353 e[2:0:-1] = [] 4354 self.assertEqual(self._subelem_tags(e), ['a0', 'a1', 'a2', 'a3']) 4355 4356 e = self._make_elem_with_children(4) 4357 e[1::-sys.maxsize] = [self.etree.Element('b')] 4358 self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3']) 4359 e[1::-sys.maxsize-1] = [self.etree.Element('c')] 4360 self.assertEqual(self._subelem_tags(e), ['a0', 'c', 'a2', 'a3']) 4361 e[1::-sys.maxsize<<64] = [self.etree.Element('d')] 4362 self.assertEqual(self._subelem_tags(e), ['a0', 'd', 'a2', 'a3']) 4363 4364 4365class _XMLPullParserTest(unittest.TestCase): 4366 etree = None 4367 4368 def _close_and_return_root(self, parser): 4369 if 'ElementTree' in self.etree.__name__: 4370 # ElementTree's API is a bit unwieldy in Py3.4 4371 root = parser._close_and_return_root() 4372 else: 4373 root = parser.close() 4374 return root 4375 4376 def _feed(self, parser, data, chunk_size=None): 4377 if chunk_size is None: 4378 parser.feed(data) 4379 else: 4380 for i in range(0, len(data), chunk_size): 4381 parser.feed(data[i:i+chunk_size]) 4382 4383 def assert_events(self, parser, expected, max_events=None): 4384 self.assertEqual( 4385 [(event, (elem.tag, elem.text)) 4386 for event, elem in islice(parser.read_events(), max_events)], 4387 expected) 4388 4389 def assert_event_tuples(self, parser, expected, max_events=None): 4390 self.assertEqual( 4391 list(islice(parser.read_events(), max_events)), 4392 expected) 4393 4394 def assert_event_tags(self, parser, expected, max_events=None): 4395 events = islice(parser.read_events(), max_events) 4396 self.assertEqual([(action, elem.tag) for action, elem in events], 4397 expected) 4398 4399 def test_simple_xml(self): 4400 for chunk_size in (None, 1, 5): 4401 #with self.subTest(chunk_size=chunk_size): 4402 parser = self.etree.XMLPullParser() 4403 self.assert_event_tags(parser, []) 4404 self._feed(parser, "<!-- comment -->\n", chunk_size) 4405 self.assert_event_tags(parser, []) 4406 self._feed(parser, 4407 "<root>\n <element key='value'>text</element", 4408 chunk_size) 4409 self.assert_event_tags(parser, []) 4410 self._feed(parser, ">\n", chunk_size) 4411 self.assert_event_tags(parser, [('end', 'element')]) 4412 self._feed(parser, "<element>text</element>tail\n", chunk_size) 4413 self._feed(parser, "<empty-element/>\n", chunk_size) 4414 self.assert_event_tags(parser, [ 4415 ('end', 'element'), 4416 ('end', 'empty-element'), 4417 ]) 4418 self._feed(parser, "</root>\n", chunk_size) 4419 self.assert_event_tags(parser, [('end', 'root')]) 4420 root = self._close_and_return_root(parser) 4421 self.assertEqual(root.tag, 'root') 4422 4423 def test_feed_while_iterating(self): 4424 parser = self.etree.XMLPullParser() 4425 it = parser.read_events() 4426 self._feed(parser, "<root>\n <element key='value'>text</element>\n") 4427 action, elem = next(it) 4428 self.assertEqual((action, elem.tag), ('end', 'element')) 4429 self._feed(parser, "</root>\n") 4430 action, elem = next(it) 4431 self.assertEqual((action, elem.tag), ('end', 'root')) 4432 with self.assertRaises(StopIteration): 4433 next(it) 4434 4435 def test_simple_xml_with_ns(self): 4436 parser = self.etree.XMLPullParser() 4437 self.assert_event_tags(parser, []) 4438 self._feed(parser, "<!-- comment -->\n") 4439 self.assert_event_tags(parser, []) 4440 self._feed(parser, "<root xmlns='namespace'>\n") 4441 self.assert_event_tags(parser, []) 4442 self._feed(parser, "<element key='value'>text</element") 4443 self.assert_event_tags(parser, []) 4444 self._feed(parser, ">\n") 4445 self.assert_event_tags(parser, [('end', '{namespace}element')]) 4446 self._feed(parser, "<element>text</element>tail\n") 4447 self._feed(parser, "<empty-element/>\n") 4448 self.assert_event_tags(parser, [ 4449 ('end', '{namespace}element'), 4450 ('end', '{namespace}empty-element'), 4451 ]) 4452 self._feed(parser, "</root>\n") 4453 self.assert_event_tags(parser, [('end', '{namespace}root')]) 4454 root = self._close_and_return_root(parser) 4455 self.assertEqual(root.tag, '{namespace}root') 4456 4457 def test_ns_events(self): 4458 parser = self.etree.XMLPullParser(events=('start-ns', 'end-ns')) 4459 self._feed(parser, "<!-- comment -->\n") 4460 self._feed(parser, "<root xmlns='namespace'>\n") 4461 self.assertEqual( 4462 list(parser.read_events()), 4463 [('start-ns', ('', 'namespace'))]) 4464 self._feed(parser, "<element key='value'>text</element") 4465 self._feed(parser, ">\n") 4466 self._feed(parser, "<element>text</element>tail\n") 4467 self._feed(parser, "<empty-element/>\n") 4468 self._feed(parser, "</root>\n") 4469 self.assertEqual(list(parser.read_events()), [('end-ns', None)]) 4470 parser.close() 4471 4472 def test_ns_events_end_ns_only(self): 4473 parser = self.etree.XMLPullParser(events=['end-ns']) 4474 self._feed(parser, "<!-- comment -->\n") 4475 self._feed(parser, "<root xmlns='namespace' xmlns:a='abc' xmlns:b='xyz'>\n") 4476 self.assertEqual(list(parser.read_events()), []) 4477 self._feed(parser, "<a:element key='value'>text</a:element") 4478 self._feed(parser, ">\n") 4479 self._feed(parser, "<b:element>text</b:element>tail\n") 4480 self._feed(parser, "<empty-element/>\n") 4481 self.assertEqual(list(parser.read_events()), []) 4482 self._feed(parser, "</root>\n") 4483 self.assertEqual(list(parser.read_events()), [ 4484 ('end-ns', None), 4485 ('end-ns', None), 4486 ('end-ns', None), 4487 ]) 4488 parser.close() 4489 4490 @et_needs_pyversion(3,8) 4491 def test_ns_events_start(self): 4492 parser = self.etree.XMLPullParser(events=('start-ns', 'start', 'end')) 4493 self._feed(parser, "<tag xmlns='abc' xmlns:p='xyz'>\n") 4494 self.assert_event_tuples(parser, [ 4495 ('start-ns', ('', 'abc')), 4496 ('start-ns', ('p', 'xyz')), 4497 ], max_events=2) 4498 self.assert_event_tags(parser, [ 4499 ('start', '{abc}tag'), 4500 ], max_events=1) 4501 4502 self._feed(parser, "<child />\n") 4503 self.assert_event_tags(parser, [ 4504 ('start', '{abc}child'), 4505 ('end', '{abc}child'), 4506 ]) 4507 4508 self._feed(parser, "</tag>\n") 4509 parser.close() 4510 self.assert_event_tags(parser, [ 4511 ('end', '{abc}tag'), 4512 ]) 4513 4514 @et_needs_pyversion(3,8) 4515 def test_ns_events_start_end(self): 4516 parser = self.etree.XMLPullParser(events=('start-ns', 'start', 'end', 'end-ns')) 4517 self._feed(parser, "<tag xmlns='abc' xmlns:p='xyz'>\n") 4518 self.assert_event_tuples(parser, [ 4519 ('start-ns', ('', 'abc')), 4520 ('start-ns', ('p', 'xyz')), 4521 ], max_events=2) 4522 self.assert_event_tags(parser, [ 4523 ('start', '{abc}tag'), 4524 ], max_events=1) 4525 4526 self._feed(parser, "<child />\n") 4527 self.assert_event_tags(parser, [ 4528 ('start', '{abc}child'), 4529 ('end', '{abc}child'), 4530 ]) 4531 4532 self._feed(parser, "</tag>\n") 4533 parser.close() 4534 self.assert_event_tags(parser, [ 4535 ('end', '{abc}tag'), 4536 ], max_events=1) 4537 self.assert_event_tuples(parser, [ 4538 ('end-ns', None), 4539 ('end-ns', None), 4540 ]) 4541 4542 def test_events(self): 4543 parser = self.etree.XMLPullParser(events=()) 4544 self._feed(parser, "<root/>\n") 4545 self.assert_event_tags(parser, []) 4546 4547 parser = self.etree.XMLPullParser(events=('start', 'end')) 4548 self._feed(parser, "<!-- text here -->\n") 4549 self.assert_events(parser, []) 4550 4551 parser = self.etree.XMLPullParser(events=('start', 'end')) 4552 self._feed(parser, "<root>\n") 4553 self.assert_event_tags(parser, [('start', 'root')]) 4554 self._feed(parser, "<element key='value'>text</element") 4555 self.assert_event_tags(parser, [('start', 'element')]) 4556 self._feed(parser, ">\n") 4557 self.assert_event_tags(parser, [('end', 'element')]) 4558 self._feed(parser, 4559 "<element xmlns='foo'>text<empty-element/></element>tail\n") 4560 self.assert_event_tags(parser, [ 4561 ('start', '{foo}element'), 4562 ('start', '{foo}empty-element'), 4563 ('end', '{foo}empty-element'), 4564 ('end', '{foo}element'), 4565 ]) 4566 self._feed(parser, "</root>") 4567 root = self._close_and_return_root(parser) 4568 self.assert_event_tags(parser, [('end', 'root')]) 4569 self.assertEqual(root.tag, 'root') 4570 4571 parser = self.etree.XMLPullParser(events=('start',)) 4572 self._feed(parser, "<!-- comment -->\n") 4573 self.assert_event_tags(parser, []) 4574 self._feed(parser, "<root>\n") 4575 self.assert_event_tags(parser, [('start', 'root')]) 4576 self._feed(parser, "<element key='value'>text</element") 4577 self.assert_event_tags(parser, [('start', 'element')]) 4578 self._feed(parser, ">\n") 4579 self.assert_event_tags(parser, []) 4580 self._feed(parser, 4581 "<element xmlns='foo'>text<empty-element/></element>tail\n") 4582 self.assert_event_tags(parser, [ 4583 ('start', '{foo}element'), 4584 ('start', '{foo}empty-element'), 4585 ]) 4586 self._feed(parser, "</root>") 4587 root = self._close_and_return_root(parser) 4588 self.assertEqual(root.tag, 'root') 4589 4590 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 4591 def test_events_comment(self): 4592 parser = self.etree.XMLPullParser(events=('start', 'comment', 'end')) 4593 self._feed(parser, "<!-- text here -->\n") 4594 self.assert_events(parser, [('comment', (self.etree.Comment, ' text here '))]) 4595 self._feed(parser, "<!-- more text here -->\n") 4596 self.assert_events(parser, [('comment', (self.etree.Comment, ' more text here '))]) 4597 self._feed(parser, "<root-tag>text") 4598 self.assert_event_tags(parser, [('start', 'root-tag')]) 4599 self._feed(parser, "<!-- inner comment-->\n") 4600 self.assert_events(parser, [('comment', (self.etree.Comment, ' inner comment'))]) 4601 self._feed(parser, "</root-tag>\n") 4602 self.assert_event_tags(parser, [('end', 'root-tag')]) 4603 self._feed(parser, "<!-- outer comment -->\n") 4604 self.assert_events(parser, [('comment', (self.etree.Comment, ' outer comment '))]) 4605 4606 parser = self.etree.XMLPullParser(events=('comment',)) 4607 self._feed(parser, "<!-- text here -->\n") 4608 self.assert_events(parser, [('comment', (self.etree.Comment, ' text here '))]) 4609 4610 @et_needs_pyversion(3, 8, 0, 'alpha', 4) 4611 def test_events_pi(self): 4612 # Note: lxml's PIs have target+text, ET's PIs have both in "text" 4613 parser = self.etree.XMLPullParser(events=('start', 'pi', 'end')) 4614 self._feed(parser, "<?pitarget?>\n") 4615 self.assert_event_tags(parser, [('pi', self.etree.PI)]) 4616 parser = self.etree.XMLPullParser(events=('pi',)) 4617 self._feed(parser, "<?pitarget some text ?>\n") 4618 self.assert_event_tags(parser, [('pi', self.etree.PI)]) 4619 4620 def test_events_sequence(self): 4621 # Test that events can be some sequence that's not just a tuple or list 4622 eventset = {'end', 'start'} 4623 parser = self.etree.XMLPullParser(events=eventset) 4624 self._feed(parser, "<foo>bar</foo>") 4625 self.assert_event_tags(parser, [('start', 'foo'), ('end', 'foo')]) 4626 4627 class DummyIter(object): 4628 def __init__(self): 4629 self.events = iter(['start', 'end', 'start-ns']) 4630 def __iter__(self): 4631 return self 4632 def __next__(self): 4633 return next(self.events) 4634 def next(self): 4635 return next(self.events) 4636 4637 parser = self.etree.XMLPullParser(events=DummyIter()) 4638 self._feed(parser, "<foo>bar</foo>") 4639 self.assert_event_tags(parser, [('start', 'foo'), ('end', 'foo')]) 4640 4641 def test_unknown_event(self): 4642 with self.assertRaises(ValueError): 4643 self.etree.XMLPullParser(events=('start', 'end', 'bogus')) 4644 4645 4646class _C14NTest(unittest.TestCase): 4647 etree = None 4648 maxDiff = None 4649 4650 if not hasattr(unittest.TestCase, 'subTest'): 4651 @contextmanager 4652 def subTest(self, name, **kwargs): 4653 try: 4654 yield 4655 except unittest.SkipTest: 4656 raise 4657 except Exception as e: 4658 print("Subtest {} failed: {}".format(name, e)) 4659 raise 4660 4661 def _canonicalize(self, input_file, **options): 4662 return self.etree.canonicalize(from_file=input_file, **options) 4663 4664 # 4665 # simple roundtrip tests (from c14n.py) 4666 4667 def c14n_roundtrip(self, xml, **options): 4668 return self.etree.canonicalize(xml, **options) 4669 4670 def test_simple_roundtrip(self): 4671 c14n_roundtrip = self.c14n_roundtrip 4672 # Basics 4673 self.assertEqual(c14n_roundtrip("<doc/>"), '<doc></doc>') 4674 self.assertEqual(c14n_roundtrip("<doc xmlns='uri'/>"), # FIXME 4675 '<doc xmlns="uri"></doc>') 4676 self.assertEqual(c14n_roundtrip("<prefix:doc xmlns:prefix='uri'/>"), 4677 '<prefix:doc xmlns:prefix="uri"></prefix:doc>') 4678 self.assertEqual(c14n_roundtrip("<doc xmlns:prefix='uri'><prefix:bar/></doc>"), 4679 '<doc><prefix:bar xmlns:prefix="uri"></prefix:bar></doc>') 4680 self.assertEqual(c14n_roundtrip("<elem xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' />"), 4681 '<elem></elem>') 4682 4683 # C14N spec 4684 self.assertEqual(c14n_roundtrip("<doc>Hello, world!<!-- Comment 1 --></doc>"), 4685 '<doc>Hello, world!</doc>') 4686 self.assertEqual(c14n_roundtrip("<value>2</value>"), 4687 '<value>2</value>') 4688 self.assertEqual(c14n_roundtrip('<compute><![CDATA[value>"0" && value<"10" ?"valid":"error"]]></compute>'), 4689 '<compute>value>"0" && value<"10" ?"valid":"error"</compute>') 4690 self.assertEqual(c14n_roundtrip('''<compute expr='value>"0" && value<"10" ?"valid":"error"'>valid</compute>'''), 4691 '<compute expr="value>"0" && value<"10" ?"valid":"error"">valid</compute>') 4692 self.assertEqual(c14n_roundtrip("<norm attr=' '   
	 ' '/>"), 4693 '<norm attr=" \' 
	 \' "></norm>') 4694 self.assertEqual(c14n_roundtrip("<normNames attr=' A   
	 B '/>"), 4695 '<normNames attr=" A 
	 B "></normNames>') 4696 self.assertEqual(c14n_roundtrip("<normId id=' '   
	 ' '/>"), 4697 '<normId id=" \' 
	 \' "></normId>') 4698 4699 # fragments from PJ's tests 4700 #self.assertEqual(c14n_roundtrip("<doc xmlns:x='http://example.com/x' xmlns='http://example.com/default'><b y:a1='1' xmlns='http://example.com/default' a3='3' xmlns:y='http://example.com/y' y:a2='2'/></doc>"), 4701 #'<doc xmlns:x="http://example.com/x"><b xmlns:y="http://example.com/y" a3="3" y:a1="1" y:a2="2"></b></doc>') 4702 4703 @et_needs_pyversion(3, 8, 7) 4704 @et_exclude_pyversion(3, 9, 0) 4705 def test_c14n_namespaces(self): 4706 c14n_roundtrip = self.c14n_roundtrip 4707 # Namespace issues 4708 # https://bugs.launchpad.net/lxml/+bug/1869455 4709 xml = '<X xmlns="http://nps/a"><Y targets="abc,xyz"></Y></X>' 4710 self.assertEqual(c14n_roundtrip(xml), xml) 4711 xml = '<X xmlns="http://nps/a"><Y xmlns="http://nsp/b" targets="abc,xyz"></Y></X>' 4712 self.assertEqual(c14n_roundtrip(xml), xml) 4713 xml = '<X xmlns="http://nps/a"><Y xmlns:b="http://nsp/b" b:targets="abc,xyz"></Y></X>' 4714 self.assertEqual(c14n_roundtrip(xml), xml) 4715 4716 def test_c14n_exclusion(self): 4717 c14n_roundtrip = self.c14n_roundtrip 4718 xml = textwrap.dedent("""\ 4719 <root xmlns:x="http://example.com/x"> 4720 <a x:attr="attrx"> 4721 <b>abtext</b> 4722 </a> 4723 <b>btext</b> 4724 <c> 4725 <x:d>dtext</x:d> 4726 </c> 4727 </root> 4728 """) 4729 self.assertEqual( 4730 c14n_roundtrip(xml, strip_text=True), 4731 '<root>' 4732 '<a xmlns:x="http://example.com/x" x:attr="attrx"><b>abtext</b></a>' 4733 '<b>btext</b>' 4734 '<c><x:d xmlns:x="http://example.com/x">dtext</x:d></c>' 4735 '</root>') 4736 self.assertEqual( 4737 c14n_roundtrip(xml, strip_text=True, exclude_attrs=['{http://example.com/x}attr']), 4738 '<root>' 4739 '<a><b>abtext</b></a>' 4740 '<b>btext</b>' 4741 '<c><x:d xmlns:x="http://example.com/x">dtext</x:d></c>' 4742 '</root>') 4743 self.assertEqual( 4744 c14n_roundtrip(xml, strip_text=True, exclude_tags=['{http://example.com/x}d']), 4745 '<root>' 4746 '<a xmlns:x="http://example.com/x" x:attr="attrx"><b>abtext</b></a>' 4747 '<b>btext</b>' 4748 '<c></c>' 4749 '</root>') 4750 self.assertEqual( 4751 c14n_roundtrip(xml, strip_text=True, exclude_attrs=['{http://example.com/x}attr'], 4752 exclude_tags=['{http://example.com/x}d']), 4753 '<root>' 4754 '<a><b>abtext</b></a>' 4755 '<b>btext</b>' 4756 '<c></c>' 4757 '</root>') 4758 self.assertEqual( 4759 c14n_roundtrip(xml, strip_text=True, exclude_tags=['a', 'b']), 4760 '<root>' 4761 '<c><x:d xmlns:x="http://example.com/x">dtext</x:d></c>' 4762 '</root>') 4763 self.assertEqual( 4764 c14n_roundtrip(xml, exclude_tags=['a', 'b']), 4765 '<root>\n' 4766 ' \n' 4767 ' \n' 4768 ' <c>\n' 4769 ' <x:d xmlns:x="http://example.com/x">dtext</x:d>\n' 4770 ' </c>\n' 4771 '</root>') 4772 self.assertEqual( 4773 c14n_roundtrip(xml, strip_text=True, exclude_tags=['{http://example.com/x}d', 'b']), 4774 '<root>' 4775 '<a xmlns:x="http://example.com/x" x:attr="attrx"></a>' 4776 '<c></c>' 4777 '</root>') 4778 self.assertEqual( 4779 c14n_roundtrip(xml, exclude_tags=['{http://example.com/x}d', 'b']), 4780 '<root>\n' 4781 ' <a xmlns:x="http://example.com/x" x:attr="attrx">\n' 4782 ' \n' 4783 ' </a>\n' 4784 ' \n' 4785 ' <c>\n' 4786 ' \n' 4787 ' </c>\n' 4788 '</root>') 4789 4790 # 4791 # basic method=c14n tests from the c14n 2.0 specification. uses 4792 # test files under xmltestdata/c14n-20. 4793 4794 # note that this uses generated C14N versions of the standard ET.write 4795 # output, not roundtripped C14N (see above). 4796 4797 def test_xml_c14n2(self): 4798 datadir = os.path.join(os.path.dirname(__file__), "c14n-20") 4799 full_path = partial(os.path.join, datadir) 4800 4801 files = [filename[:-4] for filename in sorted(os.listdir(datadir)) 4802 if filename.endswith('.xml')] 4803 input_files = [ 4804 filename for filename in files 4805 if filename.startswith('in') 4806 ] 4807 configs = { 4808 filename: { 4809 # <c14n2:PrefixRewrite>sequential</c14n2:PrefixRewrite> 4810 option.tag.split('}')[-1]: ((option.text or '').strip(), option) 4811 for option in self.etree.parse(full_path(filename) + ".xml").getroot() 4812 } 4813 for filename in files 4814 if filename.startswith('c14n') 4815 } 4816 4817 tests = { 4818 input_file: [ 4819 (filename, configs[filename.rsplit('_', 1)[-1]]) 4820 for filename in files 4821 if filename.startswith('out_%s_' % input_file) 4822 and filename.rsplit('_', 1)[-1] in configs 4823 ] 4824 for input_file in input_files 4825 } 4826 4827 # Make sure we found all test cases. 4828 self.assertEqual(30, len([ 4829 output_file for output_files in tests.values() 4830 for output_file in output_files])) 4831 4832 def get_option(config, option_name, default=None): 4833 return config.get(option_name, (default, ()))[0] 4834 4835 for input_file, output_files in tests.items(): 4836 for output_file, config in output_files: 4837 keep_comments = get_option( 4838 config, 'IgnoreComments') == 'true' # no, it's right :) 4839 strip_text = get_option( 4840 config, 'TrimTextNodes') == 'true' 4841 rewrite_prefixes = get_option( 4842 config, 'PrefixRewrite') == 'sequential' 4843 if 'QNameAware' in config: 4844 qattrs = [ 4845 "{%s}%s" % (el.get('NS'), el.get('Name')) 4846 for el in config['QNameAware'][1].findall( 4847 '{http://www.w3.org/2010/xml-c14n2}QualifiedAttr') 4848 ] 4849 qtags = [ 4850 "{%s}%s" % (el.get('NS'), el.get('Name')) 4851 for el in config['QNameAware'][1].findall( 4852 '{http://www.w3.org/2010/xml-c14n2}Element') 4853 ] 4854 else: 4855 qtags = qattrs = None 4856 4857 # Build subtest description from config. 4858 config_descr = ','.join( 4859 "%s=%s" % (name, value or ','.join(c.tag.split('}')[-1] for c in children)) 4860 for name, (value, children) in sorted(config.items()) 4861 ) 4862 4863 with self.subTest("{}({})".format(output_file, config_descr)): 4864 if input_file == 'inNsRedecl' and not rewrite_prefixes: 4865 self.skipTest( 4866 "Redeclared namespace handling is not supported in {}".format( 4867 output_file)) 4868 if input_file == 'inNsSuperfluous' and not rewrite_prefixes: 4869 self.skipTest( 4870 "Redeclared namespace handling is not supported in {}".format( 4871 output_file)) 4872 if 'QNameAware' in config and config['QNameAware'][1].find( 4873 '{http://www.w3.org/2010/xml-c14n2}XPathElement') is not None: 4874 self.skipTest( 4875 "QName rewriting in XPath text is not supported in {}".format( 4876 output_file)) 4877 4878 f = full_path(input_file + ".xml") 4879 if input_file == 'inC14N5': 4880 # Hack: avoid setting up external entity resolution in the parser. 4881 with open(full_path('world.txt'), 'rb') as entity_file: 4882 with open(f, 'rb') as f: 4883 f = io.BytesIO(f.read().replace(b'&ent2;', entity_file.read().strip())) 4884 4885 text = self._canonicalize( 4886 f, 4887 with_comments=keep_comments, 4888 strip_text=strip_text, 4889 rewrite_prefixes=rewrite_prefixes, 4890 qname_aware_tags=qtags, qname_aware_attrs=qattrs) 4891 4892 with io.open(full_path(output_file + ".xml"), 'r', encoding='utf8') as f: 4893 expected = f.read() 4894 if input_file == 'inC14N3' and self.etree is not etree: 4895 # FIXME: cET resolves default attributes but ET does not! 4896 expected = expected.replace(' attr="default"', '') 4897 text = text.replace(' attr="default"', '') 4898 self.assertEqual(expected, text) 4899 4900 4901if etree: 4902 class ETreeTestCase(_ETreeTestCaseBase): 4903 etree = etree 4904 4905 class ETreePullTestCase(_XMLPullParserTest): 4906 etree = etree 4907 4908 class ETreeElementSlicingTest(_ElementSlicingTest): 4909 etree = etree 4910 4911 class ETreeC14NTest(_C14NTest): 4912 etree = etree 4913 4914 class ETreeC14N2WriteTest(ETreeC14NTest): 4915 def _canonicalize(self, input_file, with_comments=True, strip_text=False, 4916 rewrite_prefixes=False, qname_aware_tags=None, qname_aware_attrs=None, 4917 **options): 4918 if rewrite_prefixes or qname_aware_attrs or qname_aware_tags: 4919 self.skipTest("C14N 2.0 feature not supported with ElementTree.write()") 4920 4921 parser = self.etree.XMLParser(attribute_defaults=True, collect_ids=False) 4922 tree = self.etree.parse(input_file, parser) 4923 out = io.BytesIO() 4924 tree.write( 4925 out, method='c14n2', 4926 with_comments=with_comments, strip_text=strip_text, 4927 **options) 4928 return out.getvalue().decode('utf8') 4929 4930 class ETreeC14N2TostringTest(ETreeC14NTest): 4931 def _canonicalize(self, input_file, with_comments=True, strip_text=False, 4932 rewrite_prefixes=False, qname_aware_tags=None, qname_aware_attrs=None, 4933 **options): 4934 if rewrite_prefixes or qname_aware_attrs or qname_aware_tags: 4935 self.skipTest("C14N 2.0 feature not supported with ElementTree.tostring()") 4936 4937 parser = self.etree.XMLParser(attribute_defaults=True, collect_ids=False) 4938 tree = self.etree.parse(input_file, parser) 4939 return self.etree.tostring( 4940 tree, method='c14n2', 4941 with_comments=with_comments, strip_text=strip_text, 4942 **options).decode('utf8') 4943 4944 4945if ElementTree: 4946 class ElementTreeTestCase(_ETreeTestCaseBase): 4947 etree = ElementTree 4948 4949 @classmethod 4950 def setUpClass(cls): 4951 if sys.version_info >= (3, 9): 4952 return 4953 import warnings 4954 # ElementTree warns about getiterator() in recent Pythons 4955 warnings.filterwarnings( 4956 'ignore', 4957 r'This method will be removed.*\.iter\(\).*instead', 4958 PendingDeprecationWarning) 4959 4960 filter_by_version( 4961 ElementTreeTestCase, 4962 ElementTreeTestCase.required_versions_ET, ET_VERSION) 4963 4964 if hasattr(ElementTree, 'XMLPullParser'): 4965 class ElementTreePullTestCase(_XMLPullParserTest): 4966 etree = ElementTree 4967 else: 4968 ElementTreePullTestCase = None 4969 4970 if hasattr(ElementTree, 'canonicalize'): 4971 class ElementTreeC14NTest(_C14NTest): 4972 etree = ElementTree 4973 else: 4974 ElementTreeC14NTest = None 4975 4976 class ElementTreeElementSlicingTest(_ElementSlicingTest): 4977 etree = ElementTree 4978 4979 4980if cElementTree: 4981 class CElementTreeTestCase(_ETreeTestCaseBase): 4982 etree = cElementTree 4983 4984 filter_by_version( 4985 CElementTreeTestCase, 4986 CElementTreeTestCase.required_versions_cET, CET_VERSION) 4987 4988 class CElementTreeElementSlicingTest(_ElementSlicingTest): 4989 etree = cElementTree 4990 4991 4992def test_suite(): 4993 suite = unittest.TestSuite() 4994 if etree: 4995 suite.addTests([unittest.makeSuite(ETreeTestCase)]) 4996 suite.addTests([unittest.makeSuite(ETreePullTestCase)]) 4997 suite.addTests([unittest.makeSuite(ETreeElementSlicingTest)]) 4998 suite.addTests([unittest.makeSuite(ETreeC14NTest)]) 4999 suite.addTests([unittest.makeSuite(ETreeC14N2WriteTest)]) 5000 suite.addTests([unittest.makeSuite(ETreeC14N2TostringTest)]) 5001 if ElementTree: 5002 suite.addTests([unittest.makeSuite(ElementTreeTestCase)]) 5003 if ElementTreePullTestCase: 5004 suite.addTests([unittest.makeSuite(ElementTreePullTestCase)]) 5005 if ElementTreeC14NTest: 5006 suite.addTests([unittest.makeSuite(ElementTreeC14NTest)]) 5007 suite.addTests([unittest.makeSuite(ElementTreeElementSlicingTest)]) 5008 if cElementTree: 5009 suite.addTests([unittest.makeSuite(CElementTreeTestCase)]) 5010 suite.addTests([unittest.makeSuite(CElementTreeElementSlicingTest)]) 5011 return suite 5012 5013if __name__ == '__main__': 5014 print('to test use test.py %s' % __file__) 5015