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

# Source Code for Module lxml.tests.test_etree

       1  # -*- coding: utf-8 -*-
       2
       3  """
       4  Tests specific to the extended etree API
       5
       6  Tests that apply to the general ElementTree API should go into
       7  test_elementtree
       8  """
       9
      10  from __future__ import absolute_import
      11
      12  import os.path
      13  import unittest
      14  import copy
      15  import sys
      16  import re
      17  import gc
      18  import operator
      19  import tempfile
      20  import textwrap
      21  import zlib
      22  import gzip
      23
      24  from .common_imports import etree, StringIO, BytesIO, HelperTestCase
      25  from .common_imports import fileInTestDir, fileUrlInTestDir, read_file, path2url
      26  from .common_imports import SillyFileLike, LargeFileLikeUnicode, doctest, make_doctest
      27  from .common_imports import canonicalize, sorted, _str, _bytes
      28
      29  print("")
      30  print("TESTED VERSION: %s" % etree.__version__)
      31  print("    Python:           " + repr(sys.version_info))
      32  print("    lxml.etree:       " + repr(etree.LXML_VERSION))
      33  print("    libxml used:      " + repr(etree.LIBXML_VERSION))
      34  print("    libxml compiled:  " + repr(etree.LIBXML_COMPILED_VERSION))
      35  print("    libxslt used:     " + repr(etree.LIBXSLT_VERSION))
      36  print("    libxslt compiled: " + repr(etree.LIBXSLT_COMPILED_VERSION))
      37  print("")
      38
      39  try:
      40      _unicode = unicode
      41  except NameError:
      42      # Python 3
      43      _unicode = str
      44
      45
      46 -class ETreeOnlyTestCase(HelperTestCase):
      47      """Tests only for etree, not ElementTree"""
      48      etree = etree
      49
      50 -    def test_version(self):
      51          self.assertTrue(isinstance(etree.__version__, _unicode))
      52          self.assertTrue(isinstance(etree.LXML_VERSION, tuple))
      53          self.assertEqual(len(etree.LXML_VERSION), 4)
      54          self.assertTrue(isinstance(etree.LXML_VERSION[0], int))
      55          self.assertTrue(isinstance(etree.LXML_VERSION[1], int))
      56          self.assertTrue(isinstance(etree.LXML_VERSION[2], int))
      57          self.assertTrue(isinstance(etree.LXML_VERSION[3], int))
      58          self.assertTrue(etree.__version__.startswith(
      59              str(etree.LXML_VERSION[0])))
      60
      61 -    def test_c_api(self):
      62          if hasattr(self.etree, '__pyx_capi__'):
      63              # newer Pyrex compatible C-API
      64              self.assertTrue(isinstance(self.etree.__pyx_capi__, dict))
      65              self.assertTrue(len(self.etree.__pyx_capi__) > 0)
      66          else:
      67              # older C-API mechanism
      68              self.assertTrue(hasattr(self.etree, '_import_c_api'))
      69
      70 -    def test_include_paths(self):
      71          import lxml
      72          includes = lxml.get_include()
      73          self.assertTrue(includes)
      74          self.assertTrue(len(includes) >= 2)
      75          self.assertTrue(os.path.join(os.path.dirname(lxml.__file__), 'includes') in includes,
      76                          includes)
      77
      78 -    def test_element_names(self):
      79          Element = self.etree.Element
      80          el = Element('name')
      81          self.assertEqual(el.tag, 'name')
      82          el = Element('{}name')
      83          self.assertEqual(el.tag, 'name')
      84
      85 -    def test_element_name_empty(self):
      86          Element = self.etree.Element
      87          el = Element('name')
      88          self.assertRaises(ValueError, Element, '{}')
      89          self.assertRaises(ValueError, setattr, el, 'tag', '{}')
      90
      91          self.assertRaises(ValueError, Element, '{test}')
      92          self.assertRaises(ValueError, setattr, el, 'tag', '{test}')
      93
      94 -    def test_element_name_colon(self):
      95          Element = self.etree.Element
      96          self.assertRaises(ValueError, Element, 'p:name')
      97          self.assertRaises(ValueError, Element, '{test}p:name')
      98
      99          el = Element('name')
     100          self.assertRaises(ValueError, setattr, el, 'tag', 'p:name')
     101
     102 -    def test_element_name_quote(self):
     103          Element = self.etree.Element
     104          self.assertRaises(ValueError, Element, "p'name")
     105          self.assertRaises(ValueError, Element, 'p"name')
     106
     107          self.assertRaises(ValueError, Element, "{test}p'name")
     108          self.assertRaises(ValueError, Element, '{test}p"name')
     109
     110          el = Element('name')
     111          self.assertRaises(ValueError, setattr, el, 'tag', "p'name")
     112          self.assertRaises(ValueError, setattr, el, 'tag', 'p"name')
     113
     114 -    def test_element_name_space(self):
     115          Element = self.etree.Element
     116          self.assertRaises(ValueError, Element, ' name ')
     117          self.assertRaises(ValueError, Element, 'na me')
     118          self.assertRaises(ValueError, Element, '{test} name')
     119
     120          el = Element('name')
     121          self.assertRaises(ValueError, setattr, el, 'tag', ' name ')
     122
     123 -    def test_subelement_name_empty(self):
     124          Element = self.etree.Element
     125          SubElement = self.etree.SubElement
     126
     127          el = Element('name')
     128          self.assertRaises(ValueError, SubElement, el, '{}')
     129          self.assertRaises(ValueError, SubElement, el, '{test}')
     130
     131 -    def test_subelement_name_colon(self):
     132          Element = self.etree.Element
     133          SubElement = self.etree.SubElement
     134
     135          el = Element('name')
     136          self.assertRaises(ValueError, SubElement, el, 'p:name')
     137          self.assertRaises(ValueError, SubElement, el, '{test}p:name')
     138
     139 -    def test_subelement_name_quote(self):
     140          Element = self.etree.Element
     141          SubElement = self.etree.SubElement
     142
     143          el = Element('name')
     144          self.assertRaises(ValueError, SubElement, el, "p'name")
     145          self.assertRaises(ValueError, SubElement, el, "{test}p'name")
     146
     147          self.assertRaises(ValueError, SubElement, el, 'p"name')
     148          self.assertRaises(ValueError, SubElement, el, '{test}p"name')
     149
     150 -    def test_subelement_name_space(self):
     151          Element = self.etree.Element
     152          SubElement = self.etree.SubElement
     153
     154          el = Element('name')
     155          self.assertRaises(ValueError, SubElement, el, ' name ')
     156          self.assertRaises(ValueError, SubElement, el, 'na me')
     157          self.assertRaises(ValueError, SubElement, el, '{test} name')
     158
     159 -    def test_subelement_attribute_invalid(self):
     160          Element = self.etree.Element
     161          SubElement = self.etree.SubElement
     162
     163          el = Element('name')
     164          self.assertRaises(ValueError, SubElement, el, 'name', {'a b c' : 'abc'})
     165          self.assertRaises(ValueError, SubElement, el, 'name', {'a' : 'a\0\n'})
     166          self.assertEqual(0, len(el))
     167
     168 -    def test_qname_empty(self):
     169          QName = self.etree.QName
     170          self.assertRaises(ValueError, QName, '')
     171          self.assertRaises(ValueError, QName, 'test', '')
     172
     173 -    def test_qname_colon(self):
     174          QName = self.etree.QName
     175          self.assertRaises(ValueError, QName, 'p:name')
     176          self.assertRaises(ValueError, QName, 'test', 'p:name')
     177
     178 -    def test_qname_space(self):
     179          QName = self.etree.QName
     180          self.assertRaises(ValueError, QName, ' name ')
     181          self.assertRaises(ValueError, QName, 'na me')
     182          self.assertRaises(ValueError, QName, 'test', ' name')
     183
     184 -    def test_qname_namespace_localname(self):
     185          # ET doesn't have namespace/localname properties on QNames
     186          QName = self.etree.QName
     187          namespace, localname = 'http://myns', 'a'
     188          qname = QName(namespace, localname)
     189          self.assertEqual(namespace, qname.namespace)
     190          self.assertEqual(localname, qname.localname)
     191
     192 -    def test_qname_element(self):
     193          # ET doesn't have namespace/localname properties on QNames
     194          QName = self.etree.QName
     195          qname1 = QName('http://myns', 'a')
     196          a = self.etree.Element(qname1, nsmap={'p' : 'http://myns'})
     197
     198          qname2 = QName(a)
     199          self.assertEqual(a.tag, qname1.text)
     200          self.assertEqual(qname1.text, qname2.text)
     201          self.assertEqual(qname1, qname2)
     202
     203 -    def test_qname_text_resolve(self):
     204          # ET doesn't resove QNames as text values
     205          etree = self.etree
     206          qname = etree.QName('http://myns', 'a')
     207          a = etree.Element(qname, nsmap={'p' : 'http://myns'})
     208          a.text = qname
     209
     210          self.assertEqual("p:a", a.text)
     211
     212 -    def test_nsmap_prefix_invalid(self):
     213          etree = self.etree
     214          self.assertRaises(ValueError,
     215                            etree.Element, "root", nsmap={'"' : 'testns'})
     216          self.assertRaises(ValueError,
     217                            etree.Element, "root", nsmap={'&' : 'testns'})
     218          self.assertRaises(ValueError,
     219                            etree.Element, "root", nsmap={'a:b' : 'testns'})
     220
     221 -    def test_attribute_has_key(self):
     222          # ET in Py 3.x has no "attrib.has_key()" method
     223          XML = self.etree.XML
     224
     225          root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />'))
     226          self.assertEqual(
     227              True, root.attrib.has_key('bar'))
     228          self.assertEqual(
     229              False, root.attrib.has_key('baz'))
     230          self.assertEqual(
     231              False, root.attrib.has_key('hah'))
     232          self.assertEqual(
     233              True,
     234              root.attrib.has_key('{http://ns.codespeak.net/test}baz'))
     235
     236 -    def test_attribute_set(self):
     237          Element = self.etree.Element
     238          root = Element("root")
     239          root.set("attr", "TEST")
     240          self.assertEqual("TEST", root.get("attr"))
     241
     242 -    def test_attribute_set_nonstring(self):
     243          # ElementTree accepts arbitrary attribute values
     244          # lxml.etree allows only strings
     245          Element = self.etree.Element
     246
     247          root = Element("root")
     248          root.set("attr", "TEST")
     249          self.assertEqual("TEST", root.get("attr"))
     250          self.assertRaises(TypeError, root.set, "newattr", 5)
     251
     252 -    def test_attrib_and_keywords(self):
     253          Element = self.etree.Element
     254
     255          root = Element("root")
     256          root.set("attr", "TEST")
     257          self.assertEqual("TEST", root.attrib["attr"])
     258
     259          root2 = Element("root2", root.attrib, attr2='TOAST')
     260          self.assertEqual("TEST", root2.attrib["attr"])
     261          self.assertEqual("TOAST", root2.attrib["attr2"])
     262          self.assertEqual(None, root.attrib.get("attr2"))
     263
     264 -    def test_attrib_order(self):
     265          Element = self.etree.Element
     266
     267          keys = ["attr%d" % i for i in range(10)]
     268          values = ["TEST-%d" % i for i in range(10)]
     269          items = list(zip(keys, values))
     270
     271          root = Element("root")
     272          for key, value in items:
     273              root.set(key, value)
     274          self.assertEqual(keys, root.attrib.keys())
     275          self.assertEqual(values, root.attrib.values())
     276
     277          root2 = Element("root2", root.attrib,
     278                          attr_99='TOAST-1', attr_98='TOAST-2')
     279          self.assertEqual(['attr_98', 'attr_99'] + keys,
     280                           root2.attrib.keys())
     281          self.assertEqual(['TOAST-2', 'TOAST-1'] + values,
     282                           root2.attrib.values())
     283
     284          self.assertEqual(keys, root.attrib.keys())
     285          self.assertEqual(values, root.attrib.values())
     286
     287 -    def test_attribute_set_invalid(self):
     288          # ElementTree accepts arbitrary attribute values
     289          # lxml.etree allows only strings, or None for (html5) boolean attributes
     290          Element = self.etree.Element
     291          root = Element("root")
     292          self.assertRaises(TypeError, root.set, "newattr", 5)
     293          self.assertRaises(TypeError, root.set, "newattr", object)
     294          self.assertRaises(TypeError, root.set, "newattr", None)
     295          self.assertRaises(TypeError, root.set, "newattr")
     296
     297 -    def test_strip_attributes(self):
     298          XML = self.etree.XML
     299          xml = _bytes('<test a="5" b="10" c="20"><x a="4" b="2"/></test>')
     300
     301          root = XML(xml)
     302          self.etree.strip_attributes(root, 'a')
     303          self.assertEqual(_bytes('<test b="10" c="20"><x b="2"></x></test>'),
     304                            self._writeElement(root))
     305
     306          root = XML(xml)
     307          self.etree.strip_attributes(root, 'b', 'c')
     308          self.assertEqual(_bytes('<test a="5"><x a="4"></x></test>'),
     309                            self._writeElement(root))
     310
     311 -    def test_strip_attributes_ns(self):
     312          XML = self.etree.XML
     313          xml = _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20" n:a="5"><x a="4" n:b="2"/></test>')
     314
     315          root = XML(xml)
     316          self.etree.strip_attributes(root, 'a')
     317          self.assertEqual(
     318              _bytes('<test xmlns:n="http://test/ns" b="10" c="20" n:a="5"><x n:b="2"></x></test>'),
     319              self._writeElement(root))
     320
     321          root = XML(xml)
     322          self.etree.strip_attributes(root, '{http://test/ns}a', 'c')
     323          self.assertEqual(
     324              _bytes('<test xmlns:n="http://test/ns" a="6" b="10"><x a="4" n:b="2"></x></test>'),
     325              self._writeElement(root))
     326
     327          root = XML(xml)
     328          self.etree.strip_attributes(root, '{http://test/ns}*')
     329          self.assertEqual(
     330              _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20"><x a="4"></x></test>'),
     331              self._writeElement(root))
     332
     333 -    def test_strip_elements(self):
     334          XML = self.etree.XML
     335          xml = _bytes('<test><a><b><c/></b></a><x><a><b/><c/></a></x></test>')
     336
     337          root = XML(xml)
     338          self.etree.strip_elements(root, 'a')
     339          self.assertEqual(_bytes('<test><x></x></test>'),
     340                            self._writeElement(root))
     341
     342          root = XML(xml)
     343          self.etree.strip_elements(root, 'b', 'c', 'X', 'Y', 'Z')
     344          self.assertEqual(_bytes('<test><a></a><x><a></a></x></test>'),
     345                            self._writeElement(root))
     346
     347          root = XML(xml)
     348          self.etree.strip_elements(root, 'c')
     349          self.assertEqual(_bytes('<test><a><b></b></a><x><a><b></b></a></x></test>'),
     350                            self._writeElement(root))
     351
     352 -    def test_strip_elements_ns(self):
     353          XML = self.etree.XML
     354          xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>C</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>')
     355
     356          root = XML(xml)
     357          self.etree.strip_elements(root, 'a')
     358          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X</x>XT</test>'),
     359                            self._writeElement(root))
     360
     361          root = XML(xml)
     362          self.etree.strip_elements(root, '{urn:a}b', 'c')
     363          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     364                            self._writeElement(root))
     365
     366          root = XML(xml)
     367          self.etree.strip_elements(root, '{urn:a}*', 'c')
     368          self.assertEqual(_bytes('<test>TEST<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     369                            self._writeElement(root))
     370
     371          root = XML(xml)
     372          self.etree.strip_elements(root, '{urn:a}*', 'c', with_tail=False)
     373          self.assertEqual(_bytes('<test>TESTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     374                            self._writeElement(root))
     375
     376 -    def test_strip_tags(self):
     377          XML = self.etree.XML
     378          xml = _bytes('<test>TEST<a>A<b>B<c/>CT</b>BT</a>AT<x>X<a>A<b/>BT<c/>CT</a>AT</x>XT</test>')
     379
     380          root = XML(xml)
     381          self.etree.strip_tags(root, 'a')
     382          self.assertEqual(_bytes('<test>TESTA<b>B<c></c>CT</b>BTAT<x>XA<b></b>BT<c></c>CTAT</x>XT</test>'),
     383                            self._writeElement(root))
     384
     385          root = XML(xml)
     386          self.etree.strip_tags(root, 'b', 'c', 'X', 'Y', 'Z')
     387          self.assertEqual(_bytes('<test>TEST<a>ABCTBT</a>AT<x>X<a>ABTCT</a>AT</x>XT</test>'),
     388                            self._writeElement(root))
     389
     390          root = XML(xml)
     391          self.etree.strip_tags(root, 'c')
     392          self.assertEqual(_bytes('<test>TEST<a>A<b>BCT</b>BT</a>AT<x>X<a>A<b></b>BTCT</a>AT</x>XT</test>'),
     393                            self._writeElement(root))
     394
     395 -    def test_strip_tags_pi_comment(self):
     396          XML = self.etree.XML
     397          PI = self.etree.ProcessingInstruction
     398          Comment = self.etree.Comment
     399          xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>')
     400
     401          root = XML(xml)
     402          self.etree.strip_tags(root, PI)
     403          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->\n<?PI1?>'),
     404                            self._writeElement(root))
     405
     406          root = XML(xml)
     407          self.etree.strip_tags(root, Comment)
     408          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT<?PI2?></test>\n<!--comment3-->\n<?PI1?>'),
     409                            self._writeElement(root))
     410
     411          root = XML(xml)
     412          self.etree.strip_tags(root, PI, Comment)
     413          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'),
     414                            self._writeElement(root))
     415
     416          root = XML(xml)
     417          self.etree.strip_tags(root, Comment, PI)
     418          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'),
     419                            self._writeElement(root))
     420
     421 -    def test_strip_tags_pi_comment_all(self):
     422          XML = self.etree.XML
     423          ElementTree = self.etree.ElementTree
     424          PI = self.etree.ProcessingInstruction
     425          Comment = self.etree.Comment
     426          xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>')
     427
     428          root = XML(xml)
     429          self.etree.strip_tags(ElementTree(root), PI)
     430          self.assertEqual(_bytes('<!--comment1-->\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->'),
     431                            self._writeElement(root))
     432
     433          root = XML(xml)
     434          self.etree.strip_tags(ElementTree(root), Comment)
     435          self.assertEqual(_bytes('<?PI1?>\n<test>TESTXT<?PI2?></test>\n<?PI1?>'),
     436                            self._writeElement(root))
     437
     438          root = XML(xml)
     439          self.etree.strip_tags(ElementTree(root), PI, Comment)
     440          self.assertEqual(_bytes('<test>TESTXT</test>'),
     441                            self._writeElement(root))
     442
     443          root = XML(xml)
     444          self.etree.strip_tags(ElementTree(root), Comment, PI)
     445          self.assertEqual(_bytes('<test>TESTXT</test>'),
     446                            self._writeElement(root))
     447
     448 -    def test_strip_tags_doc_style(self):
     449          XML = self.etree.XML
     450          xml = _bytes('''
     451          <div>
     452              <div>
     453                  I like <strong>sheep</strong>.
     454                  <br/>
     455                  I like lots of <strong>sheep</strong>.
     456                  <br/>
     457                  Click <a href="http://www.sheep.com">here</a>
     458                   for <a href="http://www.sheep.com">those</a> sheep.
     459                  <br/>
     460              </div>
     461          </div>
     462          '''.strip())
     463
     464          root = XML(xml)
     465          self.etree.strip_tags(root, 'a')
     466          self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''), xml).replace(_bytes('<br/>'), _bytes('<br></br>')),
     467                            self._writeElement(root))
     468
     469          root = XML(xml)
     470          self.etree.strip_tags(root, 'a', 'br')
     471          self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''),
     472                                   re.sub(_bytes('<br[^>]*>'), _bytes(''), xml)),
     473                            self._writeElement(root))
     474
     475 -    def test_strip_tags_ns(self):
     476          XML = self.etree.XML
     477          xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>CT</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>')
     478
     479          root = XML(xml)
     480          self.etree.strip_tags(root, 'a')
     481          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>XA<b xmlns="urn:a"></b>BT<c xmlns="urn:x"></c>CTAT</x>XT</test>'),
     482                            self._writeElement(root))
     483
     484          root = XML(xml)
     485          self.etree.strip_tags(root, '{urn:a}b', 'c')
     486          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     487                            self._writeElement(root))
     488
     489          root = XML(xml)
     490          self.etree.strip_tags(root, '{urn:a}*', 'c')
     491          self.assertEqual(_bytes('<test>TESTA<b>B<c xmlns="urn:c"></c>CT</b>BTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     492                            self._writeElement(root))
     493
     494 -    def test_strip_tags_and_remove(self):
     495          # previously crashed
     496          HTML = self.etree.HTML
     497          root = HTML(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'))[0][0]
     498          self.assertEqual(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'),
     499                            self.etree.tostring(root))
     500          self.etree.strip_tags(root, 'b')
     501          self.assertEqual(_bytes('<div><h1>title</h1> foo <p>boo</p></div>'),
     502                            self.etree.tostring(root))
     503          root.remove(root[0])
     504          self.assertEqual(_bytes('<div><p>boo</p></div>'),
     505                            self.etree.tostring(root))
     506
     507 -    def test_pi(self):
     508          # lxml.etree separates target and text
     509          Element = self.etree.Element
     510          SubElement = self.etree.SubElement
     511          ProcessingInstruction = self.etree.ProcessingInstruction
     512
     513          a = Element('a')
     514          a.append(ProcessingInstruction('foo', 'some more text'))
     515          self.assertEqual(a[0].target, 'foo')
     516          self.assertEqual(a[0].text, 'some more text')
     517
     518 -    def test_pi_parse(self):
     519          XML = self.etree.XML
     520          root = XML(_bytes("<test><?mypi my test ?></test>"))
     521          self.assertEqual(root[0].target, "mypi")
     522          self.assertEqual(root[0].text, "my test ")
     523
     524 -    def test_pi_pseudo_attributes_get(self):
     525          XML = self.etree.XML
     526          root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>"))
     527          self.assertEqual(root[0].target, "mypi")
     528          self.assertEqual(root[0].get('my'), "1")
     529          self.assertEqual(root[0].get('test'), " abc ")
     530          self.assertEqual(root[0].get('quotes'), "' '")
     531          self.assertEqual(root[0].get('only'), None)
     532          self.assertEqual(root[0].get('names'), None)
     533          self.assertEqual(root[0].get('nope'), None)
     534
     535 -    def test_pi_pseudo_attributes_attrib(self):
     536          XML = self.etree.XML
     537          root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>"))
     538          self.assertEqual(root[0].target, "mypi")
     539          self.assertEqual(root[0].attrib['my'], "1")
     540          self.assertEqual(root[0].attrib['test'], " abc ")
     541          self.assertEqual(root[0].attrib['quotes'], "' '")
     542          self.assertRaises(KeyError, root[0].attrib.__getitem__, 'only')
     543          self.assertRaises(KeyError, root[0].attrib.__getitem__, 'names')
     544          self.assertRaises(KeyError, root[0].attrib.__getitem__, 'nope')
     545
     546 -    def test_deepcopy_pi(self):
     547          # previously caused a crash
     548          ProcessingInstruction = self.etree.ProcessingInstruction
     549
     550          a = ProcessingInstruction("PI", "ONE")
     551          b = copy.deepcopy(a)
     552          b.text = "ANOTHER"
     553
     554          self.assertEqual('ONE',     a.text)
     555          self.assertEqual('ANOTHER', b.text)
     556
     557 -    def test_deepcopy_elementtree_pi(self):
     558          XML = self.etree.XML
     559          tostring = self.etree.tostring
     560          root = XML(_bytes("<?mypi my test ?><test/><!--comment -->"))
     561          tree1 = self.etree.ElementTree(root)
     562          self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"),
     563                            tostring(tree1))
     564
     565          tree2 = copy.deepcopy(tree1)
     566          self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"),
     567                            tostring(tree2))
     568
     569          root2 = copy.deepcopy(tree1.getroot())
     570          self.assertEqual(_bytes("<test/>"),
     571                            tostring(root2))
     572
     573 -    def test_deepcopy_elementtree_dtd(self):
     574          XML = self.etree.XML
     575          tostring = self.etree.tostring
     576          xml = _bytes('<!DOCTYPE test [\n<!ENTITY entity "tasty">\n]>\n<test/>')
     577          root = XML(xml)
     578          tree1 = self.etree.ElementTree(root)
     579          self.assertEqual(xml, tostring(tree1))
     580
     581          tree2 = copy.deepcopy(tree1)
     582          self.assertEqual(xml, tostring(tree2))
     583
     584          root2 = copy.deepcopy(tree1.getroot())
     585          self.assertEqual(_bytes("<test/>"),
     586                            tostring(root2))
     587
     588 -    def test_deepcopy_pi_dtd(self):
     589          XML = self.etree.XML
     590          tostring = self.etree.tostring
     591          xml = _bytes('<!-- comment --><!DOCTYPE test [\n<!ENTITY entity "tasty">\n]>\n<test/>')
     592          root = XML(xml)
     593          tree1 = self.etree.ElementTree(root)
     594          self.assertEqual(xml, tostring(tree1))
     595
     596          tree2 = copy.deepcopy(tree1)
     597          self.assertEqual(xml, tostring(tree2))
     598
     599 -    def test_parse_remove_comments(self):
     600          fromstring = self.etree.fromstring
     601          tostring = self.etree.tostring
     602          XMLParser = self.etree.XMLParser
     603
     604          xml = _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     605          parser = XMLParser(remove_comments=True)
     606          root = fromstring(xml, parser)
     607          self.assertEqual(
     608              _bytes('<a><b><c/></b></a>'),
     609              tostring(root))
     610
     611 -    def test_parse_remove_pis(self):
     612          parse = self.etree.parse
     613          tostring = self.etree.tostring
     614          XMLParser = self.etree.XMLParser
     615
     616          xml = _bytes('<?test?><a><?A?><b><?B?><c/></b><?C?></a><?tail?>')
     617
     618          f = BytesIO(xml)
     619          tree = parse(f)
     620          self.assertEqual(
     621              xml,
     622              tostring(tree))
     623
     624          parser = XMLParser(remove_pis=True)
     625          tree = parse(f, parser)
     626          self.assertEqual(
     627              _bytes('<a><b><c/></b></a>'),
     628              tostring(tree))
     629
     630 -    def test_parse_parser_type_error(self):
     631          # ET raises IOError only
     632          parse = self.etree.parse
     633          self.assertRaises(TypeError, parse, 'notthere.xml', object())
     634
     635 -    def test_iterparse_tree_comments(self):
     636          # ET removes comments
     637          iterparse = self.etree.iterparse
     638          tostring = self.etree.tostring
     639
     640          f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     641          events = list(iterparse(f))
     642          root = events[-1][1]
     643          self.assertEqual(3, len(events))
     644          self.assertEqual(
     645              _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'),
     646              tostring(root))
     647
     648 -    def test_iterparse_comments(self):
     649          # ET removes comments
     650          iterparse = self.etree.iterparse
     651          tostring = self.etree.tostring
     652
     653          def name(event, el):
     654              if event == 'comment':
     655                  return el.text
     656              else:
     657                  return el.tag
     658
     659          f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     660          events = list(iterparse(f, events=('end', 'comment')))
     661          root = events[-1][1]
     662          self.assertEqual(6, len(events))
     663          self.assertEqual(['A', ' B ', 'c', 'b', 'C', 'a'],
     664                            [ name(*item) for item in events ])
     665          self.assertEqual(
     666              _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'),
     667              tostring(root))
     668
     669 -    def test_iterparse_pis(self):
     670          # ET removes pis
     671          iterparse = self.etree.iterparse
     672          tostring = self.etree.tostring
     673          ElementTree = self.etree.ElementTree
     674
     675          def name(event, el):
     676              if event == 'pi':
     677                  return (el.target, el.text)
     678              else:
     679                  return el.tag
     680
     681          f = BytesIO('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>')
     682          events = list(iterparse(f, events=('end', 'pi')))
     683          root = events[-2][1]
     684          self.assertEqual(8, len(events))
     685          self.assertEqual([('pia','a'), ('pib','b'), ('pic','c'), 'c', 'b',
     686                             ('pid','d'), 'a', ('pie','e')],
     687                            [ name(*item) for item in events ])
     688          self.assertEqual(
     689              _bytes('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>'),
     690              tostring(ElementTree(root)))
     691
     692 -    def test_iterparse_remove_comments(self):
     693          iterparse = self.etree.iterparse
     694          tostring = self.etree.tostring
     695
     696          f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     697          events = list(iterparse(f, remove_comments=True,
     698                                  events=('end', 'comment')))
     699          root = events[-1][1]
     700          self.assertEqual(3, len(events))
     701          self.assertEqual(['c', 'b', 'a'],
     702                            [ el.tag for (event, el) in events ])
     703          self.assertEqual(
     704              _bytes('<a><b><c/></b></a>'),
     705              tostring(root))
     706
     707 -    def test_iterparse_broken(self):
     708          iterparse = self.etree.iterparse
     709          f = BytesIO('<a><b><c/></a>')
     710          # ET raises ExpatError, lxml raises XMLSyntaxError
     711          self.assertRaises(self.etree.XMLSyntaxError, list, iterparse(f))
     712
     713 -    def test_iterparse_broken_recover(self):
     714          iterparse = self.etree.iterparse
     715          f = BytesIO('<a><b><c/></a>')
     716          it = iterparse(f, events=('start', 'end'), recover=True)
     717          events = [(ev, el.tag) for ev, el in it]
     718          root = it.root
     719          self.assertTrue(root is not None)
     720
     721          self.assertEqual(1, events.count(('start', 'a')))
     722          self.assertEqual(1, events.count(('end', 'a')))
     723
     724          self.assertEqual(1, events.count(('start', 'b')))
     725          self.assertEqual(1, events.count(('end', 'b')))
     726
     727          self.assertEqual(1, events.count(('start', 'c')))
     728          self.assertEqual(1, events.count(('end', 'c')))
     729
     730 -    def test_iterparse_broken_multi_recover(self):
     731          iterparse = self.etree.iterparse
     732          f = BytesIO('<a><b><c/></d><b><c/></a></b>')
     733          it = iterparse(f, events=('start', 'end'), recover=True)
     734          events = [(ev, el.tag) for ev, el in it]
     735          root = it.root
     736          self.assertTrue(root is not None)
     737
     738          self.assertEqual(1, events.count(('start', 'a')))
     739          self.assertEqual(1, events.count(('end', 'a')))
     740
     741          self.assertEqual(2, events.count(('start', 'b')))
     742          self.assertEqual(2, events.count(('end', 'b')))
     743
     744          self.assertEqual(2, events.count(('start', 'c')))
     745          self.assertEqual(2, events.count(('end', 'c')))
     746
     747 -    def test_iterparse_strip(self):
     748          iterparse = self.etree.iterparse
     749          f = BytesIO("""
     750                 <a>  \n \n  <b> b test </b>  \n
     751
     752                 \n\t <c> \n </c> </a>  \n """)
     753          iterator = iterparse(f, remove_blank_text=True)
     754          text = [ (element.text, element.tail)
     755                   for event, element in iterator ]
     756          self.assertEqual(
     757              [(" b test ", None), (" \n ", None), (None, None)],
     758              text)
     759
     760 -    def test_iterparse_tag(self):
     761          iterparse = self.etree.iterparse
     762          f = BytesIO('<a><b><d/></b><c/></a>')
     763
     764          iterator = iterparse(f, tag="b", events=('start', 'end'))
     765          events = list(iterator)
     766          root = iterator.root
     767          self.assertEqual(
     768              [('start', root[0]), ('end', root[0])],
     769              events)
     770
     771 -    def test_iterparse_tag_all(self):
     772          iterparse = self.etree.iterparse
     773          f = BytesIO('<a><b><d/></b><c/></a>')
     774
     775          iterator = iterparse(f, tag="*", events=('start', 'end'))
     776          events = list(iterator)
     777          self.assertEqual(
     778              8,
     779              len(events))
     780
     781 -    def test_iterparse_tag_ns(self):
     782          iterparse = self.etree.iterparse
     783          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     784
     785          iterator = iterparse(f, tag="{urn:test:1}b", events=('start', 'end'))
     786          events = list(iterator)
     787          root = iterator.root
     788          self.assertEqual(
     789              [('start', root[0]), ('end', root[0])],
     790              events)
     791
     792 -    def test_iterparse_tag_ns_empty(self):
     793          iterparse = self.etree.iterparse
     794          f = BytesIO('<a><b><d/></b><c/></a>')
     795          iterator = iterparse(f, tag="{}b", events=('start', 'end'))
     796          events = list(iterator)
     797          root = iterator.root
     798          self.assertEqual(
     799              [('start', root[0]), ('end', root[0])],
     800              events)
     801
     802          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     803          iterator = iterparse(f, tag="{}b", events=('start', 'end'))
     804          events = list(iterator)
     805          root = iterator.root
     806          self.assertEqual([], events)
     807
     808 -    def test_iterparse_tag_ns_all(self):
     809          iterparse = self.etree.iterparse
     810          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     811          iterator = iterparse(f, tag="{urn:test:1}*", events=('start', 'end'))
     812          events = list(iterator)
     813          self.assertEqual(8, len(events))
     814
     815 -    def test_iterparse_tag_ns_empty_all(self):
     816          iterparse = self.etree.iterparse
     817          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     818          iterator = iterparse(f, tag="{}*", events=('start', 'end'))
     819          events = list(iterator)
     820          self.assertEqual([], events)
     821
     822          f = BytesIO('<a><b><d/></b><c/></a>')
     823          iterator = iterparse(f, tag="{}*", events=('start', 'end'))
     824          events = list(iterator)
     825          self.assertEqual(8, len(events))
     826
     827 -    def test_iterparse_encoding_error(self):
     828          text = _str('Søk på nettet')
     829          wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>"
     830          xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text)
     831                        ).encode('iso-8859-1')
     832
     833          self.assertRaises(self.etree.ParseError,
     834                            list, self.etree.iterparse(BytesIO(xml_latin1)))
     835
     836 -    def test_iterparse_encoding_8bit_override(self):
     837          text = _str('Søk på nettet', encoding="UTF-8")
     838          wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>"
     839          xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text)
     840                        ).encode('iso-8859-1')
     841
     842          iterator = self.etree.iterparse(BytesIO(xml_latin1),
     843                                          encoding="iso-8859-1")
     844          self.assertEqual(1, len(list(iterator)))
     845
     846          a = iterator.root
     847          self.assertEqual(a.text, text)
     848
     849 -    def test_iterparse_keep_cdata(self):
     850          tostring = self.etree.tostring
     851          f = BytesIO('<root><![CDATA[test]]></root>')
     852          context = self.etree.iterparse(f, strip_cdata=False)
     853          content = [ el.text for event,el in context ]
     854
     855          self.assertEqual(['test'], content)
     856          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
     857                            tostring(context.root))
     858
     859 -    def test_parser_encoding_unknown(self):
     860          self.assertRaises(
     861              LookupError, self.etree.XMLParser, encoding="hopefully unknown")
     862
     863 -    def test_parser_encoding(self):
     864          self.etree.XMLParser(encoding="ascii")
     865          self.etree.XMLParser(encoding="utf-8")
     866          self.etree.XMLParser(encoding="iso-8859-1")
     867
     868 -    def test_feed_parser_recover(self):
     869          parser = self.etree.XMLParser(recover=True)
     870
     871          parser.feed('<?xml version=')
     872          parser.feed('"1.0"?><ro')
     873          parser.feed('ot><')
     874          parser.feed('a test="works"')
     875          parser.feed('><othertag/></root') # <a> not closed!
     876          parser.feed('>')
     877
     878          root = parser.close()
     879
     880          self.assertEqual(root.tag, "root")
     881          self.assertEqual(len(root), 1)
     882          self.assertEqual(root[0].tag, "a")
     883          self.assertEqual(root[0].get("test"), "works")
     884          self.assertEqual(len(root[0]), 1)
     885          self.assertEqual(root[0][0].tag, "othertag")
     886          # FIXME: would be nice to get some errors logged ...
     887          #self.assertTrue(len(parser.error_log) > 0, "error log is empty")
     888
     889 -    def test_feed_parser_recover_no_id_dict(self):
     890          # test that recover mode plays nicely with the no-id-dict setup
     891          parser = self.etree.XMLParser(recover=True, collect_ids=False)
     892
     893          parser.feed('<?xml version=')
     894          parser.feed('"1.0"?><ro')
     895          parser.feed('ot xml:id="123"><')
     896          parser.feed('a test="works" xml:id=')
     897          parser.feed('"321"><othertag/></root') # <a> not closed!
     898          parser.feed('>')
     899
     900          root = parser.close()
     901
     902          self.assertEqual(root.tag, "root")
     903          self.assertEqual(len(root), 1)
     904          self.assertEqual(root[0].tag, "a")
     905          self.assertEqual(root[0].get("test"), "works")
     906          self.assertEqual(root[0].attrib, {
     907              'test': 'works',
     908              '{http://www.w3.org/XML/1998/namespace}id': '321'})
     909          self.assertEqual(len(root[0]), 1)
     910          self.assertEqual(root[0][0].tag, "othertag")
     911          # FIXME: would be nice to get some errors logged ...
     912          #self.assertTrue(len(parser.error_log) > 0, "error log is empty")
     913
     914 -    def test_elementtree_parser_target_type_error(self):
     915          assertEqual = self.assertEqual
     916          assertFalse  = self.assertFalse
     917
     918          events = []
     919          class Target(object):
     920              def start(self, tag, attrib):
     921                  events.append("start")
     922                  assertFalse(attrib)
     923                  assertEqual("TAG", tag)
     924              def end(self, tag):
     925                  events.append("end")
     926                  assertEqual("TAG", tag)
     927              def close(self):
     928                  return "DONE" # no Element!
     929
     930          parser = self.etree.XMLParser(target=Target())
     931          tree = self.etree.ElementTree()
     932
     933          self.assertRaises(TypeError,
     934                            tree.parse, BytesIO("<TAG/>"), parser=parser)
     935          self.assertEqual(["start", "end"], events)
     936
     937 -    def test_parser_target_feed_exception(self):
     938          # ET doesn't call .close() on errors
     939          events = []
     940          class Target(object):
     941              def start(self, tag, attrib):
     942                  events.append("start-" + tag)
     943              def end(self, tag):
     944                  events.append("end-" + tag)
     945                  if tag == 'a':
     946                      raise ValueError("dead and gone")
     947              def data(self, data):
     948                  events.append("data-" + data)
     949              def close(self):
     950                  events.append("close")
     951                  return "DONE"
     952
     953          parser = self.etree.XMLParser(target=Target())
     954
     955          try:
     956              parser.feed(_bytes('<root>A<a>ca</a>B</root>'))
     957              done = parser.close()
     958              self.fail("error expected, but parsing succeeded")
     959          except ValueError:
     960              done = 'value error received as expected'
     961
     962          self.assertEqual(["start-root", "data-A", "start-a",
     963                             "data-ca", "end-a", "close"],
     964                            events)
     965
     966 -    def test_parser_target_fromstring_exception(self):
     967          # ET doesn't call .close() on errors
     968          events = []
     969          class Target(object):
     970              def start(self, tag, attrib):
     971                  events.append("start-" + tag)
     972              def end(self, tag):
     973                  events.append("end-" + tag)
     974                  if tag == 'a':
     975                      raise ValueError("dead and gone")
     976              def data(self, data):
     977                  events.append("data-" + data)
     978              def close(self):
     979                  events.append("close")
     980                  return "DONE"
     981
     982          parser = self.etree.XMLParser(target=Target())
     983
     984          try:
     985              done = self.etree.fromstring(_bytes('<root>A<a>ca</a>B</root>'),
     986                                           parser=parser)
     987              self.fail("error expected, but parsing succeeded")
     988          except ValueError:
     989              done = 'value error received as expected'
     990
     991          self.assertEqual(["start-root", "data-A", "start-a",
     992                            "data-ca", "end-a", "close"],
     993                           events)
     994
     995 -    def test_parser_target_feed_no_id_dict(self):
     996          # test that target parsing works nicely with the no-id-hash setup
     997          events = []
     998          class Target(object):
     999              def start(self, tag, attrib):
    1000                  events.append("start-" + tag)
    1001              def end(self, tag):
    1002                  events.append("end-" + tag)
    1003              def data(self, data):
    1004                  events.append("data-" + data)
    1005              def comment(self, text):
    1006                  events.append("comment-" + text)
    1007              def close(self):
    1008                  return "DONE"
    1009
    1010          parser = self.etree.XMLParser(target=Target(), collect_ids=False)
    1011
    1012          parser.feed(_bytes('<!--a--><root xml:id="123">A<!--b-->'))
    1013          parser.feed(_bytes('<sub xml:id="321"/>B</root>'))
    1014          done = parser.close()
    1015
    1016          self.assertEqual("DONE", done)
    1017          self.assertEqual(["comment-a", "start-root", "data-A", "comment-b",
    1018                            "start-sub", "end-sub", "data-B", "end-root"],
    1019                           events)
    1020
    1021 -    def test_parser_target_comment(self):
    1022          events = []
    1023          class Target(object):
    1024              def start(self, tag, attrib):
    1025                  events.append("start-" + tag)
    1026              def end(self, tag):
    1027                  events.append("end-" + tag)
    1028              def data(self, data):
    1029                  events.append("data-" + data)
    1030              def comment(self, text):
    1031                  events.append("comment-" + text)
    1032              def close(self):
    1033                  return "DONE"
    1034
    1035          parser = self.etree.XMLParser(target=Target())
    1036
    1037          parser.feed(_bytes('<!--a--><root>A<!--b--><sub/><!--c-->B</root><!--d-->'))
    1038          done = parser.close()
    1039
    1040          self.assertEqual("DONE", done)
    1041          self.assertEqual(["comment-a", "start-root", "data-A", "comment-b",
    1042                             "start-sub", "end-sub", "comment-c", "data-B",
    1043                             "end-root", "comment-d"],
    1044                            events)
    1045
    1046 -    def test_parser_target_pi(self):
    1047          events = []
    1048          class Target(object):
    1049              def start(self, tag, attrib):
    1050                  events.append("start-" + tag)
    1051              def end(self, tag):
    1052                  events.append("end-" + tag)
    1053              def data(self, data):
    1054                  events.append("data-" + data)
    1055              def pi(self, target, data):
    1056                  events.append("pi-" + target + "-" + data)
    1057              def close(self):
    1058                  return "DONE"
    1059
    1060          parser = self.etree.XMLParser(target=Target())
    1061
    1062          parser.feed(_bytes('<?test a?><root>A<?test b?>B</root><?test c?>'))
    1063          done = parser.close()
    1064
    1065          self.assertEqual("DONE", done)
    1066          self.assertEqual(["pi-test-a", "start-root", "data-A", "pi-test-b",
    1067                             "data-B", "end-root", "pi-test-c"],
    1068                            events)
    1069
    1070 -    def test_parser_target_cdata(self):
    1071          events = []
    1072          class Target(object):
    1073              def start(self, tag, attrib):
    1074                  events.append("start-" + tag)
    1075              def end(self, tag):
    1076                  events.append("end-" + tag)
    1077              def data(self, data):
    1078                  events.append("data-" + data)
    1079              def close(self):
    1080                  return "DONE"
    1081
    1082          parser = self.etree.XMLParser(target=Target(),
    1083                                        strip_cdata=False)
    1084
    1085          parser.feed(_bytes('<root>A<a><![CDATA[ca]]></a>B</root>'))
    1086          done = parser.close()
    1087
    1088          self.assertEqual("DONE", done)
    1089          self.assertEqual(["start-root", "data-A", "start-a",
    1090                             "data-ca", "end-a", "data-B", "end-root"],
    1091                            events)
    1092
    1093 -    def test_parser_target_recover(self):
    1094          events = []
    1095          class Target(object):
    1096              def start(self, tag, attrib):
    1097                  events.append("start-" + tag)
    1098              def end(self, tag):
    1099                  events.append("end-" + tag)
    1100              def data(self, data):
    1101                  events.append("data-" + data)
    1102              def close(self):
    1103                  events.append("close")
    1104                  return "DONE"
    1105
    1106          parser = self.etree.XMLParser(target=Target(),
    1107                                        recover=True)
    1108
    1109          parser.feed(_bytes('<root>A<a>ca</a>B</not-root>'))
    1110          done = parser.close()
    1111
    1112          self.assertEqual("DONE", done)
    1113          self.assertEqual(["start-root", "data-A", "start-a",
    1114                             "data-ca", "end-a", "data-B",
    1115                             "end-root", "close"],
    1116                            events)
    1117
    1118 -    def test_iterwalk_tag(self):
    1119          iterwalk = self.etree.iterwalk
    1120          root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>'))
    1121
    1122          iterator = iterwalk(root, tag="b", events=('start', 'end'))
    1123          events = list(iterator)
    1124          self.assertEqual(
    1125              [('start', root[0]), ('end', root[0])],
    1126              events)
    1127
    1128 -    def test_iterwalk_tag_all(self):
    1129          iterwalk = self.etree.iterwalk
    1130          root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>'))
    1131
    1132          iterator = iterwalk(root, tag="*", events=('start', 'end'))
    1133          events = list(iterator)
    1134          self.assertEqual(
    1135              8,
    1136              len(events))
    1137
    1138 -    def test_iterwalk(self):
    1139          iterwalk = self.etree.iterwalk
    1140          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1141
    1142          events = list(iterwalk(root))
    1143          self.assertEqual(
    1144              [('end', root[0]), ('end', root[1]), ('end', root)],
    1145              events)
    1146
    1147 -    def test_iterwalk_start(self):
    1148          iterwalk = self.etree.iterwalk
    1149          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1150
    1151          iterator = iterwalk(root, events=('start',))
    1152          events = list(iterator)
    1153          self.assertEqual(
    1154              [('start', root), ('start', root[0]), ('start', root[1])],
    1155              events)
    1156
    1157 -    def test_iterwalk_start_end(self):
    1158          iterwalk = self.etree.iterwalk
    1159          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1160
    1161          iterator = iterwalk(root, events=('start','end'))
    1162          events = list(iterator)
    1163          self.assertEqual(
    1164              [('start', root), ('start', root[0]), ('end', root[0]),
    1165               ('start', root[1]), ('end', root[1]), ('end', root)],
    1166              events)
    1167
    1168 -    def test_iterwalk_clear(self):
    1169          iterwalk = self.etree.iterwalk
    1170          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1171
    1172          iterator = iterwalk(root)
    1173          for event, elem in iterator:
    1174              elem.clear()
    1175
    1176          self.assertEqual(0,
    1177                            len(root))
    1178
    1179 -    def test_iterwalk_attrib_ns(self):
    1180          iterwalk = self.etree.iterwalk
    1181          root = self.etree.XML(_bytes('<a xmlns="ns1"><b><c xmlns="ns2"/></b></a>'))
    1182
    1183          attr_name = '{testns}bla'
    1184          events = []
    1185          iterator = iterwalk(root, events=('start','end','start-ns','end-ns'))
    1186          for event, elem in iterator:
    1187              events.append(event)
    1188              if event == 'start':
    1189                  if elem.tag != '{ns1}a':
    1190                      elem.set(attr_name, 'value')
    1191
    1192          self.assertEqual(
    1193              ['start-ns', 'start', 'start', 'start-ns', 'start',
    1194               'end', 'end-ns', 'end', 'end', 'end-ns'],
    1195              events)
    1196
    1197          self.assertEqual(
    1198              None,
    1199              root.get(attr_name))
    1200          self.assertEqual(
    1201              'value',
    1202              root[0].get(attr_name))
    1203
    1204 -    def test_iterwalk_getiterator(self):
    1205          iterwalk = self.etree.iterwalk
    1206          root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>'))
    1207
    1208          counts = []
    1209          for event, elem in iterwalk(root):
    1210              counts.append(len(list(elem.getiterator())))
    1211          self.assertEqual(
    1212              [1,2,1,4],
    1213              counts)
    1214
    1215 -    def test_resolve_string_dtd(self):
    1216          parse = self.etree.parse
    1217          parser = self.etree.XMLParser(dtd_validation=True)
    1218          assertEqual = self.assertEqual
    1219          test_url = _str("__nosuch.dtd")
    1220
    1221          class MyResolver(self.etree.Resolver):
    1222              def resolve(self, url, id, context):
    1223                  assertEqual(url, test_url)
    1224                  return self.resolve_string(
    1225                      _str('''<!ENTITY myentity "%s">
    1226                          <!ELEMENT doc ANY>''') % url, context)
    1227
    1228          parser.resolvers.add(MyResolver())
    1229
    1230          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1231          tree = parse(StringIO(xml), parser)
    1232          root = tree.getroot()
    1233          self.assertEqual(root.text, test_url)
    1234
    1235 -    def test_resolve_bytes_dtd(self):
    1236          parse = self.etree.parse
    1237          parser = self.etree.XMLParser(dtd_validation=True)
    1238          assertEqual = self.assertEqual
    1239          test_url = _str("__nosuch.dtd")
    1240
    1241          class MyResolver(self.etree.Resolver):
    1242              def resolve(self, url, id, context):
    1243                  assertEqual(url, test_url)
    1244                  return self.resolve_string(
    1245                      (_str('''<!ENTITY myentity "%s">
    1246                               <!ELEMENT doc ANY>''') % url).encode('utf-8'),
    1247                      context)
    1248
    1249          parser.resolvers.add(MyResolver())
    1250
    1251          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1252          tree = parse(StringIO(xml), parser)
    1253          root = tree.getroot()
    1254          self.assertEqual(root.text, test_url)
    1255
    1256 -    def test_resolve_filelike_dtd(self):
    1257          parse = self.etree.parse
    1258          parser = self.etree.XMLParser(dtd_validation=True)
    1259          assertEqual = self.assertEqual
    1260          test_url = _str("__nosuch.dtd")
    1261
    1262          class MyResolver(self.etree.Resolver):
    1263              def resolve(self, url, id, context):
    1264                  assertEqual(url, test_url)
    1265                  return self.resolve_file(
    1266                      SillyFileLike(
    1267                          _str('''<!ENTITY myentity "%s">
    1268                          <!ELEMENT doc ANY>''') % url), context)
    1269
    1270          parser.resolvers.add(MyResolver())
    1271
    1272          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1273          tree = parse(StringIO(xml), parser)
    1274          root = tree.getroot()
    1275          self.assertEqual(root.text, test_url)
    1276
    1277 -    def test_resolve_filename_dtd(self):
    1278          parse = self.etree.parse
    1279          parser = self.etree.XMLParser(attribute_defaults=True)
    1280          assertEqual = self.assertEqual
    1281          test_url = _str("__nosuch.dtd")
    1282
    1283          class MyResolver(self.etree.Resolver):
    1284              def resolve(self, url, id, context):
    1285                  assertEqual(url, test_url)
    1286                  return self.resolve_filename(
    1287                      fileInTestDir('test.dtd'), context)
    1288
    1289          parser.resolvers.add(MyResolver())
    1290
    1291          xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url
    1292          tree = parse(StringIO(xml), parser)
    1293          root = tree.getroot()
    1294          self.assertEqual(
    1295              root.attrib,    {'default': 'valueA'})
    1296          self.assertEqual(
    1297              root[0].attrib, {'default': 'valueB'})
    1298
    1299 -    def test_resolve_filename_dtd_relative(self):
    1300          parse = self.etree.parse
    1301          parser = self.etree.XMLParser(attribute_defaults=True)
    1302          assertEqual = self.assertEqual
    1303          test_url = _str("__nosuch.dtd")
    1304
    1305          class MyResolver(self.etree.Resolver):
    1306              def resolve(self, url, id, context):
    1307                  expected = fileUrlInTestDir(test_url)
    1308                  url = url.replace('file://', 'file:')  # depends on libxml2 version
    1309                  expected = expected.replace('file://', 'file:')
    1310                  assertEqual(url, expected)
    1311                  return self.resolve_filename(
    1312                      fileUrlInTestDir('test.dtd'), context)
    1313
    1314          parser.resolvers.add(MyResolver())
    1315
    1316          xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url
    1317          tree = parse(StringIO(xml), parser,
    1318                       base_url=fileUrlInTestDir('__test.xml'))
    1319          root = tree.getroot()
    1320          self.assertEqual(
    1321              root.attrib,    {'default': 'valueA'})
    1322          self.assertEqual(
    1323              root[0].attrib, {'default': 'valueB'})
    1324
    1325 -    def test_resolve_file_dtd(self):
    1326          parse = self.etree.parse
    1327          parser = self.etree.XMLParser(attribute_defaults=True)
    1328          assertEqual = self.assertEqual
    1329          test_url = _str("__nosuch.dtd")
    1330
    1331          class MyResolver(self.etree.Resolver):
    1332              def resolve(self, url, id, context):
    1333                  assertEqual(url, test_url)
    1334                  return self.resolve_file(
    1335                      open(fileInTestDir('test.dtd'), 'rb'), context)
    1336
    1337          parser.resolvers.add(MyResolver())
    1338
    1339          xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url
    1340          tree = parse(StringIO(xml), parser)
    1341          root = tree.getroot()
    1342          self.assertEqual(
    1343              root.attrib,    {'default': 'valueA'})
    1344          self.assertEqual(
    1345              root[0].attrib, {'default': 'valueB'})
    1346
    1347 -    def test_resolve_empty(self):
    1348          parse = self.etree.parse
    1349          parser = self.etree.XMLParser(load_dtd=True)
    1350          assertEqual = self.assertEqual
    1351          test_url = _str("__nosuch.dtd")
    1352
    1353          class check(object):
    1354              resolved = False
    1355
    1356          class MyResolver(self.etree.Resolver):
    1357              def resolve(self, url, id, context):
    1358                  assertEqual(url, test_url)
    1359                  check.resolved = True
    1360                  return self.resolve_empty(context)
    1361
    1362          parser.resolvers.add(MyResolver())
    1363
    1364          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1365          self.assertRaises(etree.XMLSyntaxError, parse, StringIO(xml), parser)
    1366          self.assertTrue(check.resolved)
    1367
    1368 -    def test_resolve_error(self):
    1369          parse = self.etree.parse
    1370          parser = self.etree.XMLParser(dtd_validation=True)
    1371
    1372          class _LocalException(Exception):
    1373              pass
    1374
    1375          class MyResolver(self.etree.Resolver):
    1376              def resolve(self, url, id, context):
    1377                  raise _LocalException
    1378
    1379          parser.resolvers.add(MyResolver())
    1380
    1381          xml = '<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>'
    1382          self.assertRaises(_LocalException, parse, BytesIO(xml), parser)
    1383
    1384      if etree.LIBXML_VERSION > (2,6,20):
    1385 -        def test_entity_parse(self):
    1386              parse = self.etree.parse
    1387              tostring = self.etree.tostring
    1388              parser = self.etree.XMLParser(resolve_entities=False)
    1389              Entity = self.etree.Entity
    1390
    1391              xml = _bytes('<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>')
    1392              tree = parse(BytesIO(xml), parser)
    1393              root = tree.getroot()
    1394              self.assertEqual(root[0].tag, Entity)
    1395              self.assertEqual(root[0].text, "&myentity;")
    1396              self.assertEqual(root[0].tail, None)
    1397              self.assertEqual(root[0].name, "myentity")
    1398
    1399              self.assertEqual(_bytes('<doc>&myentity;</doc>'),
    1400                                tostring(root))
    1401
    1402 -        def test_entity_restructure(self):
    1403              xml = _bytes('''<!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]>
    1404                  <root>
    1405                    <child1/>
    1406                    <child2/>
    1407                    <child3>&nbsp;</child3>
    1408                  </root>''')
    1409
    1410              parser = self.etree.XMLParser(resolve_entities=False)
    1411              root = etree.fromstring(xml, parser)
    1412              self.assertEqual([ el.tag for el in root ],
    1413                                ['child1', 'child2', 'child3'])
    1414
    1415              root[0] = root[-1]
    1416              self.assertEqual([ el.tag for el in root ],
    1417                                ['child3', 'child2'])
    1418              self.assertEqual(root[0][0].text, '&nbsp;')
    1419              self.assertEqual(root[0][0].name, 'nbsp')
    1420
    1421 -    def test_entity_append(self):
    1422          Entity = self.etree.Entity
    1423          Element = self.etree.Element
    1424          tostring = self.etree.tostring
    1425
    1426          root = Element("root")
    1427          root.append( Entity("test") )
    1428
    1429          self.assertEqual(root[0].tag, Entity)
    1430          self.assertEqual(root[0].text, "&test;")
    1431          self.assertEqual(root[0].tail, None)
    1432          self.assertEqual(root[0].name, "test")
    1433
    1434          self.assertEqual(_bytes('<root>&test;</root>'),
    1435                            tostring(root))
    1436
    1437 -    def test_entity_values(self):
    1438          Entity = self.etree.Entity
    1439          self.assertEqual(Entity("test").text, '&test;')
    1440          self.assertEqual(Entity("#17683").text, '&#17683;')
    1441          self.assertEqual(Entity("#x1768").text, '&#x1768;')
    1442          self.assertEqual(Entity("#x98AF").text, '&#x98AF;')
    1443
    1444 -    def test_entity_error(self):
    1445          Entity = self.etree.Entity
    1446          self.assertRaises(ValueError, Entity, 'a b c')
    1447          self.assertRaises(ValueError, Entity, 'a,b')
    1448          self.assertRaises(ValueError, Entity, 'a\0b')
    1449          self.assertRaises(ValueError, Entity, '#abc')
    1450          self.assertRaises(ValueError, Entity, '#xxyz')
    1451
    1452 -    def test_cdata(self):
    1453          CDATA = self.etree.CDATA
    1454          Element = self.etree.Element
    1455          tostring = self.etree.tostring
    1456
    1457          root = Element("root")
    1458          root.text = CDATA('test')
    1459
    1460          self.assertEqual('test',
    1461                            root.text)
    1462          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1463                            tostring(root))
    1464
    1465 -    def test_cdata_tail(self):
    1466          CDATA = self.etree.CDATA
    1467          Element = self.etree.Element
    1468          SubElement = self.etree.SubElement
    1469          tostring = self.etree.tostring
    1470
    1471          root = Element("root")
    1472          child = SubElement(root, 'child')
    1473          child.tail = CDATA('test')
    1474
    1475          self.assertEqual('test', child.tail)
    1476          self.assertEqual(_bytes('<root><child/><![CDATA[test]]></root>'),
    1477                           tostring(root))
    1478
    1479          root = Element("root")
    1480          root.tail = CDATA('test')
    1481
    1482          self.assertEqual('test', root.tail)
    1483          self.assertEqual(_bytes('<root/><![CDATA[test]]>'),
    1484                           tostring(root))
    1485
    1486 -    def test_cdata_type(self):
    1487          CDATA = self.etree.CDATA
    1488          Element = self.etree.Element
    1489          root = Element("root")
    1490
    1491          root.text = CDATA("test")
    1492          self.assertEqual('test', root.text)
    1493
    1494          root.text = CDATA(_str("test"))
    1495          self.assertEqual('test', root.text)
    1496
    1497          self.assertRaises(TypeError, CDATA, 1)
    1498
    1499 -    def test_cdata_errors(self):
    1500          CDATA = self.etree.CDATA
    1501          Element = self.etree.Element
    1502
    1503          root = Element("root")
    1504          cdata = CDATA('test')
    1505
    1506          self.assertRaises(TypeError,
    1507                            root.set, 'attr', cdata)
    1508          self.assertRaises(TypeError,
    1509                            operator.setitem, root.attrib, 'attr', cdata)
    1510
    1511 -    def test_cdata_parser(self):
    1512          tostring = self.etree.tostring
    1513          parser = self.etree.XMLParser(strip_cdata=False)
    1514          root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser)
    1515
    1516          self.assertEqual('test', root.text)
    1517          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1518                            tostring(root))
    1519
    1520 -    def test_cdata_xpath(self):
    1521          tostring = self.etree.tostring
    1522          parser = self.etree.XMLParser(strip_cdata=False)
    1523          root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser)
    1524          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1525                            tostring(root))
    1526
    1527          self.assertEqual(['test'], root.xpath('//text()'))
    1528
    1529      # TypeError in etree, AssertionError in ElementTree;
    1530 -    def test_setitem_assert(self):
    1531          Element = self.etree.Element
    1532          SubElement = self.etree.SubElement
    1533
    1534          a = Element('a')
    1535          b = SubElement(a, 'b')
    1536
    1537          self.assertRaises(TypeError,
    1538                            a.__setitem__, 0, 'foo')
    1539
    1540 -    def test_append_error(self):
    1541          Element = self.etree.Element
    1542          root = Element('root')
    1543          # raises AssertionError in ElementTree
    1544          self.assertRaises(TypeError, root.append, None)
    1545          self.assertRaises(TypeError, root.extend, [None])
    1546          self.assertRaises(TypeError, root.extend, [Element('one'), None])
    1547          self.assertEqual('one', root[0].tag)
    1548
    1549 -    def test_append_recursive_error(self):
    1550          Element = self.etree.Element
    1551          SubElement = self.etree.SubElement
    1552          root = Element('root')
    1553          self.assertRaises(ValueError, root.append, root)
    1554          child = SubElement(root, 'child')
    1555          self.assertRaises(ValueError, child.append, root)
    1556          child2 = SubElement(child, 'child2')
    1557          self.assertRaises(ValueError, child2.append, root)
    1558          self.assertRaises(ValueError, child2.append, child)
    1559          self.assertEqual('child2', root[0][0].tag)
    1560
    1561 -    def test_addnext(self):
    1562          Element = self.etree.Element
    1563          SubElement = self.etree.SubElement
    1564          root = Element('root')
    1565          SubElement(root, 'a')
    1566          SubElement(root, 'b')
    1567
    1568          self.assertEqual(['a', 'b'],
    1569                            [c.tag for c in root])
    1570          root[1].addnext(root[0])
    1571          self.assertEqual(['b', 'a'],
    1572                            [c.tag for c in root])
    1573
    1574 -    def test_addprevious(self):
    1575          Element = self.etree.Element
    1576          SubElement = self.etree.SubElement
    1577          root = Element('root')
    1578          SubElement(root, 'a')
    1579          SubElement(root, 'b')
    1580
    1581          self.assertEqual(['a', 'b'],
    1582                            [c.tag for c in root])
    1583          root[0].addprevious(root[1])
    1584          self.assertEqual(['b', 'a'],
    1585                            [c.tag for c in root])
    1586
    1587 -    def test_addnext_cycle(self):
    1588          Element = self.etree.Element
    1589          SubElement = self.etree.SubElement
    1590          root = Element('root')
    1591          a = SubElement(root, 'a')
    1592          b = SubElement(a, 'b')
    1593          # appending parent as sibling is forbidden
    1594          self.assertRaises(ValueError, b.addnext, a)
    1595          self.assertEqual(['a'], [c.tag for c in root])
    1596          self.assertEqual(['b'], [c.tag for c in a])
    1597
    1598 -    def test_addprevious_cycle(self):
    1599          Element = self.etree.Element
    1600          SubElement = self.etree.SubElement
    1601          root = Element('root')
    1602          a = SubElement(root, 'a')
    1603          b = SubElement(a, 'b')
    1604          # appending parent as sibling is forbidden
    1605          self.assertRaises(ValueError, b.addprevious, a)
    1606          self.assertEqual(['a'], [c.tag for c in root])
    1607          self.assertEqual(['b'], [c.tag for c in a])
    1608
    1609 -    def test_addnext_cycle_long(self):
    1610          Element = self.etree.Element
    1611          SubElement = self.etree.SubElement
    1612          root = Element('root')
    1613          a = SubElement(root, 'a')
    1614          b = SubElement(a, 'b')
    1615          c = SubElement(b, 'c')
    1616          # appending parent as sibling is forbidden
    1617          self.assertRaises(ValueError, c.addnext, a)
    1618
    1619 -    def test_addprevious_cycle_long(self):
    1620          Element = self.etree.Element
    1621          SubElement = self.etree.SubElement
    1622          root = Element('root')
    1623          a = SubElement(root, 'a')
    1624          b = SubElement(a, 'b')
    1625          c = SubElement(b, 'c')
    1626          # appending parent as sibling is forbidden
    1627          self.assertRaises(ValueError, c.addprevious, a)
    1628
    1629 -    def test_addprevious_noops(self):
    1630          Element = self.etree.Element
    1631          SubElement = self.etree.SubElement
    1632          root = Element('root')
    1633          a = SubElement(root, 'a')
    1634          b = SubElement(root, 'b')
    1635          a.addprevious(a)
    1636          self.assertEqual('a', root[0].tag)
    1637          self.assertEqual('b', root[1].tag)
    1638          b.addprevious(b)
    1639          self.assertEqual('a', root[0].tag)
    1640          self.assertEqual('b', root[1].tag)
    1641          b.addprevious(a)
    1642          self.assertEqual('a', root[0].tag)
    1643          self.assertEqual('b', root[1].tag)
    1644
    1645 -    def test_addnext_noops(self):
    1646          Element = self.etree.Element
    1647          SubElement = self.etree.SubElement
    1648          root = Element('root')
    1649          a = SubElement(root, 'a')
    1650          b = SubElement(root, 'b')
    1651          a.addnext(a)
    1652          self.assertEqual('a', root[0].tag)
    1653          self.assertEqual('b', root[1].tag)
    1654          b.addnext(b)
    1655          self.assertEqual('a', root[0].tag)
    1656          self.assertEqual('b', root[1].tag)
    1657          a.addnext(b)
    1658          self.assertEqual('a', root[0].tag)
    1659          self.assertEqual('b', root[1].tag)
    1660
    1661 -    def test_addnext_root(self):
    1662          Element = self.etree.Element
    1663          a = Element('a')
    1664          b = Element('b')
    1665          self.assertRaises(TypeError, a.addnext, b)
    1666
    1667 -    def test_addprevious_pi(self):
    1668          Element = self.etree.Element
    1669          SubElement = self.etree.SubElement
    1670          PI = self.etree.PI
    1671          root = Element('root')
    1672          SubElement(root, 'a')
    1673          pi = PI('TARGET', 'TEXT')
    1674          pi.tail = "TAIL"
    1675
    1676          self.assertEqual(_bytes('<root><a></a></root>'),
    1677                            self._writeElement(root))
    1678          root[0].addprevious(pi)
    1679          self.assertEqual(_bytes('<root><?TARGET TEXT?>TAIL<a></a></root>'),
    1680                            self._writeElement(root))
    1681
    1682 -    def test_addprevious_root_pi(self):
    1683          Element = self.etree.Element
    1684          PI = self.etree.PI
    1685          root = Element('root')
    1686          pi = PI('TARGET', 'TEXT')
    1687          pi.tail = "TAIL"
    1688
    1689          self.assertEqual(_bytes('<root></root>'),
    1690                            self._writeElement(root))
    1691          root.addprevious(pi)
    1692          self.assertEqual(_bytes('<?TARGET TEXT?>\n<root></root>'),
    1693                            self._writeElement(root))
    1694
    1695 -    def test_addnext_pi(self):
    1696          Element = self.etree.Element
    1697          SubElement = self.etree.SubElement
    1698          PI = self.etree.PI
    1699          root = Element('root')
    1700          SubElement(root, 'a')
    1701          pi = PI('TARGET', 'TEXT')
    1702          pi.tail = "TAIL"
    1703
    1704          self.assertEqual(_bytes('<root><a></a></root>'),
    1705                            self._writeElement(root))
    1706          root[0].addnext(pi)
    1707          self.assertEqual(_bytes('<root><a></a><?TARGET TEXT?>TAIL</root>'),
    1708                            self._writeElement(root))
    1709
    1710 -    def test_addnext_root_pi(self):
    1711          Element = self.etree.Element
    1712          PI = self.etree.PI
    1713          root = Element('root')
    1714          pi = PI('TARGET', 'TEXT')
    1715          pi.tail = "TAIL"
    1716
    1717          self.assertEqual(_bytes('<root></root>'),
    1718                            self._writeElement(root))
    1719          root.addnext(pi)
    1720          self.assertEqual(_bytes('<root></root>\n<?TARGET TEXT?>'),
    1721                            self._writeElement(root))
    1722
    1723 -    def test_addnext_comment(self):
    1724          Element = self.etree.Element
    1725          SubElement = self.etree.SubElement
    1726          Comment = self.etree.Comment
    1727          root = Element('root')
    1728          SubElement(root, 'a')
    1729          comment = Comment('TEXT ')
    1730          comment.tail = "TAIL"
    1731
    1732          self.assertEqual(_bytes('<root><a></a></root>'),
    1733                            self._writeElement(root))
    1734          root[0].addnext(comment)
    1735          self.assertEqual(_bytes('<root><a></a><!--TEXT -->TAIL</root>'),
    1736                            self._writeElement(root))
    1737
    1738 -    def test_addnext_root_comment(self):
    1739          Element = self.etree.Element
    1740          Comment = self.etree.Comment
    1741          root = Element('root')
    1742          comment = Comment('TEXT ')
    1743          comment.tail = "TAIL"
    1744
    1745          self.assertEqual(_bytes('<root></root>'),
    1746                            self._writeElement(root))
    1747          root.addnext(comment)
    1748          self.assertEqual(_bytes('<root></root>\n<!--TEXT -->'),
    1749                            self._writeElement(root))
    1750
    1751 -    def test_addprevious_comment(self):
    1752          Element = self.etree.Element
    1753          SubElement = self.etree.SubElement
    1754          Comment = self.etree.Comment
    1755          root = Element('root')
    1756          SubElement(root, 'a')
    1757          comment = Comment('TEXT ')
    1758          comment.tail = "TAIL"
    1759
    1760          self.assertEqual(_bytes('<root><a></a></root>'),
    1761                            self._writeElement(root))
    1762          root[0].addprevious(comment)
    1763          self.assertEqual(_bytes('<root><!--TEXT -->TAIL<a></a></root>'),
    1764                            self._writeElement(root))
    1765
    1766 -    def test_addprevious_root_comment(self):
    1767          Element = self.etree.Element
    1768          Comment = self.etree.Comment
    1769          root = Element('root')
    1770          comment = Comment('TEXT ')
    1771          comment.tail = "TAIL"
    1772
    1773          self.assertEqual(_bytes('<root></root>'),
    1774                            self._writeElement(root))
    1775          root.addprevious(comment)
    1776          self.assertEqual(_bytes('<!--TEXT -->\n<root></root>'),
    1777                            self._writeElement(root))
    1778
    1779      # ET's Elements have items() and key(), but not values()
    1780 -    def test_attribute_values(self):
    1781          XML = self.etree.XML
    1782
    1783          root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>'))
    1784          values = root.values()
    1785          values.sort()
    1786          self.assertEqual(['Alpha', 'Beta', 'Gamma'], values)
    1787
    1788      # gives error in ElementTree
    1789 -    def test_comment_empty(self):
    1790          Element = self.etree.Element
    1791          Comment = self.etree.Comment
    1792
    1793          a = Element('a')
    1794          a.append(Comment())
    1795          self.assertEqual(
    1796              _bytes('<a><!----></a>'),
    1797              self._writeElement(a))
    1798
    1799      # ElementTree ignores comments
    1800 -    def test_comment_parse_empty(self):
    1801          ElementTree = self.etree.ElementTree
    1802          tostring = self.etree.tostring
    1803
    1804          xml = _bytes('<a><b/><!----><c/></a>')
    1805          f = BytesIO(xml)
    1806          doc = ElementTree(file=f)
    1807          a = doc.getroot()
    1808          self.assertEqual(
    1809              '',
    1810              a[1].text)
    1811          self.assertEqual(
    1812              xml,
    1813              tostring(a))
    1814
    1815      # ElementTree ignores comments
    1816 -    def test_comment_no_proxy_yet(self):
    1817          ElementTree = self.etree.ElementTree
    1818
    1819          f = BytesIO('<a><b></b><!-- hoi --><c></c></a>')
    1820          doc = ElementTree(file=f)
    1821          a = doc.getroot()
    1822          self.assertEqual(
    1823              ' hoi ',
    1824              a[1].text)
    1825
    1826      # does not raise an exception in ElementTree
    1827 -    def test_comment_immutable(self):
    1828          Element = self.etree.Element
    1829          Comment = self.etree.Comment
    1830
    1831          c = Comment()
    1832          el = Element('myel')
    1833
    1834          self.assertRaises(TypeError, c.append, el)
    1835          self.assertRaises(TypeError, c.insert, 0, el)
    1836          self.assertRaises(TypeError, c.set, "myattr", "test")
    1837
    1838 -    def test_comment_immutable_attrib(self):
    1839          c = self.etree.Comment()
    1840          self.assertEqual(0, len(c.attrib))
    1841
    1842          self.assertFalse(c.attrib.__contains__('nope'))
    1843          self.assertFalse('nope' in c.attrib)
    1844          self.assertFalse('nope' in c.attrib.keys())
    1845          self.assertFalse('nope' in c.attrib.values())
    1846          self.assertFalse(('nope', 'huhu') in c.attrib.items())
    1847
    1848          self.assertEqual([], list(c.attrib))
    1849          self.assertEqual([], list(c.attrib.keys()))
    1850          self.assertEqual([], list(c.attrib.items()))
    1851          self.assertEqual([], list(c.attrib.values()))
    1852          self.assertEqual([], list(c.attrib.iterkeys()))
    1853          self.assertEqual([], list(c.attrib.iteritems()))
    1854          self.assertEqual([], list(c.attrib.itervalues()))
    1855
    1856          self.assertEqual('HUHU', c.attrib.pop('nope', 'HUHU'))
    1857          self.assertRaises(KeyError, c.attrib.pop, 'nope')
    1858
    1859          self.assertRaises(KeyError, c.attrib.__getitem__, 'only')
    1860          self.assertRaises(KeyError, c.attrib.__getitem__, 'names')
    1861          self.assertRaises(KeyError, c.attrib.__getitem__, 'nope')
    1862          self.assertRaises(KeyError, c.attrib.__setitem__, 'nope', 'yep')
    1863          self.assertRaises(KeyError, c.attrib.__delitem__, 'nope')
    1864
    1865      # test passing 'None' to dump()
    1866 -    def test_dump_none(self):
    1867          self.assertRaises(TypeError, self.etree.dump, None)
    1868
    1869 -    def test_prefix(self):
    1870          ElementTree = self.etree.ElementTree
    1871
    1872          f = BytesIO('<a xmlns:foo="http://www.infrae.com/ns/1"><foo:b/></a>')
    1873          doc = ElementTree(file=f)
    1874          a = doc.getroot()
    1875          self.assertEqual(
    1876              None,
    1877              a.prefix)
    1878          self.assertEqual(
    1879              'foo',
    1880              a[0].prefix)
    1881
    1882 -    def test_prefix_default_ns(self):
    1883          ElementTree = self.etree.ElementTree
    1884
    1885          f = BytesIO('<a xmlns="http://www.infrae.com/ns/1"><b/></a>')
    1886          doc = ElementTree(file=f)
    1887          a = doc.getroot()
    1888          self.assertEqual(
    1889              None,
    1890              a.prefix)
    1891          self.assertEqual(
    1892              None,
    1893              a[0].prefix)
    1894
    1895 -    def test_getparent(self):
    1896          Element = self.etree.Element
    1897          SubElement = self.etree.SubElement
    1898
    1899          a = Element('a')
    1900          b = SubElement(a, 'b')
    1901          c = SubElement(a, 'c')
    1902          d = SubElement(b, 'd')
    1903          self.assertEqual(
    1904              None,
    1905              a.getparent())
    1906          self.assertEqual(
    1907              a,
    1908              b.getparent())
    1909          self.assertEqual(
    1910              b.getparent(),
    1911              c.getparent())
    1912          self.assertEqual(
    1913              b,
    1914              d.getparent())
    1915
    1916 -    def test_iterchildren(self):
    1917          XML = self.etree.XML
    1918
    1919          root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>'))
    1920          result = []
    1921          for el in root.iterchildren():
    1922              result.append(el.tag)
    1923          self.assertEqual(['one', 'two', 'three'], result)
    1924
    1925 -    def test_iterchildren_reversed(self):
    1926          XML = self.etree.XML
    1927
    1928          root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>'))
    1929          result = []
    1930          for el in root.iterchildren(reversed=True):
    1931              result.append(el.tag)
    1932          self.assertEqual(['three', 'two', 'one'], result)
    1933
    1934 -    def test_iterchildren_tag(self):
    1935          XML = self.etree.XML
    1936
    1937          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    1938          result = []
    1939          for el in root.iterchildren(tag='two'):
    1940              result.append(el.text)
    1941          self.assertEqual(['Two', 'Bla'], result)
    1942
    1943 -    def test_iterchildren_tag_posarg(self):
    1944          XML = self.etree.XML
    1945
    1946          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    1947          result = []
    1948          for el in root.iterchildren('two'):
    1949              result.append(el.text)
    1950          self.assertEqual(['Two', 'Bla'], result)
    1951
    1952 -    def test_iterchildren_tag_reversed(self):
    1953          XML = self.etree.XML
    1954
    1955          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    1956          result = []
    1957          for el in root.iterchildren(reversed=True, tag='two'):
    1958              result.append(el.text)
    1959          self.assertEqual(['Bla', 'Two'], result)
    1960
    1961 -    def test_iterchildren_tag_multiple(self):
    1962          XML = self.etree.XML
    1963
    1964          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    1965          result = []
    1966          for el in root.iterchildren(tag=['two', 'three']):
    1967              result.append(el.text)
    1968          self.assertEqual(['Two', 'Bla', None], result)
    1969
    1970 -    def test_iterchildren_tag_multiple_posarg(self):
    1971          XML = self.etree.XML
    1972
    1973          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    1974          result = []
    1975          for el in root.iterchildren('two', 'three'):
    1976              result.append(el.text)
    1977          self.assertEqual(['Two', 'Bla', None], result)
    1978
    1979 -    def test_iterchildren_tag_multiple_reversed(self):
    1980          XML = self.etree.XML
    1981
    1982          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    1983          result = []
    1984          for el in root.iterchildren(reversed=True, tag=['two', 'three']):
    1985              result.append(el.text)
    1986          self.assertEqual([None, 'Bla', 'Two'], result)
    1987
    1988 -    def test_iterancestors(self):
    1989          Element    = self.etree.Element
    1990          SubElement = self.etree.SubElement
    1991
    1992          a = Element('a')
    1993          b = SubElement(a, 'b')
    1994          c = SubElement(a, 'c')
    1995          d = SubElement(b, 'd')
    1996          self.assertEqual(
    1997              [],
    1998              list(a.iterancestors()))
    1999          self.assertEqual(
    2000              [a],
    2001              list(b.iterancestors()))
    2002          self.assertEqual(
    2003              [a],
    2004              list(c.iterancestors()))
    2005          self.assertEqual(
    2006              [b, a],
    2007              list(d.iterancestors()))
    2008
    2009 -    def test_iterancestors_tag(self):
    2010          Element    = self.etree.Element
    2011          SubElement = self.etree.SubElement
    2012
    2013          a = Element('a')
    2014          b = SubElement(a, 'b')
    2015          c = SubElement(a, 'c')
    2016          d = SubElement(b, 'd')
    2017          self.assertEqual(
    2018              [a],
    2019              list(d.iterancestors('a')))
    2020          self.assertEqual(
    2021              [a],
    2022              list(d.iterancestors(tag='a')))
    2023
    2024          self.assertEqual(
    2025              [b, a],
    2026              list(d.iterancestors('*')))
    2027          self.assertEqual(
    2028              [b, a],
    2029              list(d.iterancestors(tag='*')))
    2030
    2031 -    def test_iterancestors_tag_multiple(self):
    2032          Element    = self.etree.Element
    2033          SubElement = self.etree.SubElement
    2034
    2035          a = Element('a')
    2036          b = SubElement(a, 'b')
    2037          c = SubElement(a, 'c')
    2038          d = SubElement(b, 'd')
    2039          self.assertEqual(
    2040              [b, a],
    2041              list(d.iterancestors(tag=('a', 'b'))))
    2042          self.assertEqual(
    2043              [b, a],
    2044              list(d.iterancestors('a', 'b')))
    2045
    2046          self.assertEqual(
    2047              [],
    2048              list(d.iterancestors(tag=('w', 'x', 'y', 'z'))))
    2049          self.assertEqual(
    2050              [],
    2051              list(d.iterancestors('w', 'x', 'y', 'z')))
    2052
    2053          self.assertEqual(
    2054              [],
    2055              list(d.iterancestors(tag=('d', 'x'))))
    2056          self.assertEqual(
    2057              [],
    2058              list(d.iterancestors('d', 'x')))
    2059
    2060          self.assertEqual(
    2061              [b, a],
    2062              list(d.iterancestors(tag=('b', '*'))))
    2063          self.assertEqual(
    2064              [b, a],
    2065              list(d.iterancestors('b', '*')))
    2066
    2067          self.assertEqual(
    2068              [b],
    2069              list(d.iterancestors(tag=('b', 'c'))))
    2070          self.assertEqual(
    2071              [b],
    2072              list(d.iterancestors('b', 'c')))
    2073
    2074 -    def test_iterdescendants(self):
    2075          Element = self.etree.Element
    2076          SubElement = self.etree.SubElement
    2077
    2078          a = Element('a')
    2079          b = SubElement(a, 'b')
    2080          c = SubElement(a, 'c')
    2081          d = SubElement(b, 'd')
    2082          e = SubElement(c, 'e')
    2083
    2084          self.assertEqual(
    2085              [b, d, c, e],
    2086              list(a.iterdescendants()))
    2087          self.assertEqual(
    2088              [],
    2089              list(d.iterdescendants()))
    2090
    2091 -    def test_iterdescendants_tag(self):
    2092          Element = self.etree.Element
    2093          SubElement = self.etree.SubElement
    2094
    2095          a = Element('a')
    2096          b = SubElement(a, 'b')
    2097          c = SubElement(a, 'c')
    2098          d = SubElement(b, 'd')
    2099          e = SubElement(c, 'e')
    2100
    2101          self.assertEqual(
    2102              [],
    2103              list(a.iterdescendants('a')))
    2104          self.assertEqual(
    2105              [],
    2106              list(a.iterdescendants(tag='a')))
    2107
    2108          a2 = SubElement(e, 'a')
    2109          self.assertEqual(
    2110              [a2],
    2111              list(a.iterdescendants('a')))
    2112
    2113          self.assertEqual(
    2114              [a2],
    2115              list(c.iterdescendants('a')))
    2116          self.assertEqual(
    2117              [a2],
    2118              list(c.iterdescendants(tag='a')))
    2119
    2120 -    def test_iterdescendants_tag_multiple(self):
    2121          Element = self.etree.Element
    2122          SubElement = self.etree.SubElement
    2123
    2124          a = Element('a')
    2125          b = SubElement(a, 'b')
    2126          c = SubElement(a, 'c')
    2127          d = SubElement(b, 'd')
    2128          e = SubElement(c, 'e')
    2129
    2130          self.assertEqual(
    2131              [b, e],
    2132              list(a.iterdescendants(tag=('a', 'b', 'e'))))
    2133          self.assertEqual(
    2134              [b, e],
    2135              list(a.iterdescendants('a', 'b', 'e')))
    2136
    2137          a2 = SubElement(e, 'a')
    2138          self.assertEqual(
    2139              [b, a2],
    2140              list(a.iterdescendants(tag=('a', 'b'))))
    2141          self.assertEqual(
    2142              [b, a2],
    2143              list(a.iterdescendants('a', 'b')))
    2144
    2145          self.assertEqual(
    2146              [],
    2147              list(c.iterdescendants(tag=('x', 'y', 'z'))))
    2148          self.assertEqual(
    2149              [],
    2150              list(c.iterdescendants('x', 'y', 'z')))
    2151
    2152          self.assertEqual(
    2153              [b, d, c, e, a2],
    2154              list(a.iterdescendants(tag=('x', 'y', 'z', '*'))))
    2155          self.assertEqual(
    2156              [b, d, c, e, a2],
    2157              list(a.iterdescendants('x', 'y', 'z', '*')))
    2158
    2159 -    def test_getroottree(self):
    2160          Element = self.etree.Element
    2161          SubElement = self.etree.SubElement
    2162
    2163          a = Element('a')
    2164          b = SubElement(a, 'b')
    2165          c = SubElement(a, 'c')
    2166          d = SubElement(b, 'd')
    2167          self.assertEqual(
    2168              a,
    2169              a.getroottree().getroot())
    2170          self.assertEqual(
    2171              a,
    2172              b.getroottree().getroot())
    2173          self.assertEqual(
    2174              a,
    2175              d.getroottree().getroot())
    2176
    2177 -    def test_getnext(self):
    2178          Element    = self.etree.Element
    2179          SubElement = self.etree.SubElement
    2180
    2181          a = Element('a')
    2182          b = SubElement(a, 'b')
    2183          c = SubElement(a, 'c')
    2184          self.assertEqual(
    2185              None,
    2186              a.getnext())
    2187          self.assertEqual(
    2188              c,
    2189              b.getnext())
    2190          self.assertEqual(
    2191              None,
    2192              c.getnext())
    2193
    2194 -    def test_getprevious(self):
    2195          Element    = self.etree.Element
    2196          SubElement = self.etree.SubElement
    2197
    2198          a = Element('a')
    2199          b = SubElement(a, 'b')
    2200          c = SubElement(a, 'c')
    2201          d = SubElement(b, 'd')
    2202          self.assertEqual(
    2203              None,
    2204              a.getprevious())
    2205          self.assertEqual(
    2206              b,
    2207              c.getprevious())
    2208          self.assertEqual(
    2209              None,
    2210              b.getprevious())
    2211
    2212 -    def test_itersiblings(self):
    2213          Element    = self.etree.Element
    2214          SubElement = self.etree.SubElement
    2215
    2216          a = Element('a')
    2217          b = SubElement(a, 'b')
    2218          c = SubElement(a, 'c')
    2219          d = SubElement(b, 'd')
    2220          self.assertEqual(
    2221              [],
    2222              list(a.itersiblings()))
    2223          self.assertEqual(
    2224              [c],
    2225              list(b.itersiblings()))
    2226          self.assertEqual(
    2227              [],
    2228              list(c.itersiblings()))
    2229          self.assertEqual(
    2230              [b],
    2231              list(c.itersiblings(preceding=True)))
    2232          self.assertEqual(
    2233              [],
    2234              list(b.itersiblings(preceding=True)))
    2235
    2236 -    def test_itersiblings_tag(self):
    2237          Element    = self.etree.Element
    2238          SubElement = self.etree.SubElement
    2239
    2240          a = Element('a')
    2241          b = SubElement(a, 'b')
    2242          c = SubElement(a, 'c')
    2243          d = SubElement(b, 'd')
    2244          self.assertEqual(
    2245              [],
    2246              list(a.itersiblings(tag='XXX')))
    2247          self.assertEqual(
    2248              [c],
    2249              list(b.itersiblings(tag='c')))
    2250          self.assertEqual(
    2251              [c],
    2252              list(b.itersiblings(tag='*')))
    2253          self.assertEqual(
    2254              [b],
    2255              list(c.itersiblings(preceding=True, tag='b')))
    2256          self.assertEqual(
    2257              [],
    2258              list(c.itersiblings(preceding=True, tag='c')))
    2259
    2260 -    def test_itersiblings_tag_multiple(self):
    2261          Element    = self.etree.Element
    2262          SubElement = self.etree.SubElement
    2263
    2264          a = Element('a')
    2265          b = SubElement(a, 'b')
    2266          c = SubElement(a, 'c')
    2267          d = SubElement(b, 'd')
    2268          e = SubElement(a, 'e')
    2269          self.assertEqual(
    2270              [],
    2271              list(a.itersiblings(tag=('XXX', 'YYY'))))
    2272          self.assertEqual(
    2273              [c, e],
    2274              list(b.itersiblings(tag=('c', 'd', 'e'))))
    2275          self.assertEqual(
    2276              [b],
    2277              list(c.itersiblings(preceding=True, tag=('b', 'b', 'c', 'd'))))
    2278          self.assertEqual(
    2279              [c, b],
    2280              list(e.itersiblings(preceding=True, tag=('c', '*'))))
    2281
    2282 -    def test_parseid(self):
    2283          parseid = self.etree.parseid
    2284          XML     = self.etree.XML
    2285          xml_text = _bytes('''
    2286          <!DOCTYPE document [
    2287          <!ELEMENT document (h1,p)*>
    2288          <!ELEMENT h1 (#PCDATA)>
    2289          <!ATTLIST h1 myid ID #REQUIRED>
    2290          <!ELEMENT p  (#PCDATA)>
    2291          <!ATTLIST p  someid ID #REQUIRED>
    2292          ]>
    2293          <document>
    2294            <h1 myid="chapter1">...</h1>
    2295            <p id="note1" class="note">...</p>
    2296            <p>Regular paragraph.</p>
    2297            <p xml:id="xmlid">XML:ID paragraph.</p>
    2298            <p someid="warn1" class="warning">...</p>
    2299          </document>
    2300          ''')
    2301
    2302          tree, dic = parseid(BytesIO(xml_text))
    2303          root = tree.getroot()
    2304          root2 = XML(xml_text)
    2305          self.assertEqual(self._writeElement(root),
    2306                            self._writeElement(root2))
    2307          expected = {
    2308              "chapter1" : root[0],
    2309              "xmlid"    : root[3],
    2310              "warn1"    : root[4]
    2311              }
    2312          self.assertTrue("chapter1" in dic)
    2313          self.assertTrue("warn1" in dic)
    2314          self.assertTrue("xmlid" in dic)
    2315          self._checkIDDict(dic, expected)
    2316
    2317 -    def test_XMLDTDID(self):
    2318          XMLDTDID = self.etree.XMLDTDID
    2319          XML      = self.etree.XML
    2320          xml_text = _bytes('''
    2321          <!DOCTYPE document [
    2322          <!ELEMENT document (h1,p)*>
    2323          <!ELEMENT h1 (#PCDATA)>
    2324          <!ATTLIST h1 myid ID #REQUIRED>
    2325          <!ELEMENT p  (#PCDATA)>
    2326          <!ATTLIST p  someid ID #REQUIRED>
    2327          ]>
    2328          <document>
    2329            <h1 myid="chapter1">...</h1>
    2330            <p id="note1" class="note">...</p>
    2331            <p>Regular paragraph.</p>
    2332            <p xml:id="xmlid">XML:ID paragraph.</p>
    2333            <p someid="warn1" class="warning">...</p>
    2334          </document>
    2335          ''')
    2336
    2337          root, dic = XMLDTDID(xml_text)
    2338          root2 = XML(xml_text)
    2339          self.assertEqual(self._writeElement(root),
    2340                            self._writeElement(root2))
    2341          expected = {
    2342              "chapter1" : root[0],
    2343              "xmlid"    : root[3],
    2344              "warn1"    : root[4]
    2345              }
    2346          self.assertTrue("chapter1" in dic)
    2347          self.assertTrue("warn1" in dic)
    2348          self.assertTrue("xmlid" in dic)
    2349          self._checkIDDict(dic, expected)
    2350
    2351 -    def test_XMLDTDID_empty(self):
    2352          XMLDTDID = self.etree.XMLDTDID
    2353          XML      = self.etree.XML
    2354          xml_text = _bytes('''
    2355          <document>
    2356            <h1 myid="chapter1">...</h1>
    2357            <p id="note1" class="note">...</p>
    2358            <p>Regular paragraph.</p>
    2359            <p someid="warn1" class="warning">...</p>
    2360          </document>
    2361          ''')
    2362
    2363          root, dic = XMLDTDID(xml_text)
    2364          root2 = XML(xml_text)
    2365          self.assertEqual(self._writeElement(root),
    2366                            self._writeElement(root2))
    2367          expected = {}
    2368          self._checkIDDict(dic, expected)
    2369
    2370 -    def test_XMLDTDID_no_id_dict(self):
    2371          XMLDTDID = self.etree.XMLDTDID
    2372          XML      = self.etree.XML
    2373          xml_text = _bytes('''
    2374          <!DOCTYPE document [
    2375          <!ELEMENT document (h1,p)*>
    2376          <!ELEMENT h1 (#PCDATA)>
    2377          <!ATTLIST h1 myid ID #REQUIRED>
    2378          <!ELEMENT p  (#PCDATA)>
    2379          <!ATTLIST p  someid ID #REQUIRED>
    2380          ]>
    2381          <document>
    2382            <h1 myid="chapter1">...</h1>
    2383            <p id="note1" class="note">...</p>
    2384            <p>Regular paragraph.</p>
    2385            <p xml:id="xmlid">XML:ID paragraph.</p>
    2386            <p someid="warn1" class="warning">...</p>
    2387          </document>
    2388          ''')
    2389
    2390          parser = etree.XMLParser(collect_ids=False)
    2391          root, dic = XMLDTDID(xml_text, parser=parser)
    2392          root2 = XML(xml_text)
    2393          self.assertEqual(self._writeElement(root),
    2394                           self._writeElement(root2))
    2395          self.assertFalse(dic)
    2396          self._checkIDDict(dic, {})
    2397
    2398 -    def _checkIDDict(self, dic, expected):
    2399          self.assertEqual(len(dic),
    2400                            len(expected))
    2401          self.assertEqual(sorted(dic.items()),
    2402                            sorted(expected.items()))
    2403          if sys.version_info < (3,):
    2404              self.assertEqual(sorted(dic.iteritems()),
    2405                                sorted(expected.iteritems()))
    2406          self.assertEqual(sorted(dic.keys()),
    2407                            sorted(expected.keys()))
    2408          if sys.version_info < (3,):
    2409              self.assertEqual(sorted(dic.iterkeys()),
    2410                                sorted(expected.iterkeys()))
    2411          if sys.version_info < (3,):
    2412              self.assertEqual(sorted(dic.values()),
    2413                                sorted(expected.values()))
    2414              self.assertEqual(sorted(dic.itervalues()),
    2415                                sorted(expected.itervalues()))
    2416
    2417 -    def test_namespaces(self):
    2418          etree = self.etree
    2419
    2420          r = {'foo': 'http://ns.infrae.com/foo'}
    2421          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2422          self.assertEqual(
    2423              'foo',
    2424              e.prefix)
    2425          self.assertEqual(
    2426              _bytes('<foo:bar xmlns:foo="http://ns.infrae.com/foo"></foo:bar>'),
    2427              self._writeElement(e))
    2428
    2429 -    def test_namespaces_default(self):
    2430          etree = self.etree
    2431
    2432          r = {None: 'http://ns.infrae.com/foo'}
    2433          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2434          self.assertEqual(
    2435              None,
    2436              e.prefix)
    2437          self.assertEqual(
    2438              '{http://ns.infrae.com/foo}bar',
    2439              e.tag)
    2440          self.assertEqual(
    2441              _bytes('<bar xmlns="http://ns.infrae.com/foo"></bar>'),
    2442              self._writeElement(e))
    2443
    2444 -    def test_namespaces_default_and_other(self):
    2445          etree = self.etree
    2446
    2447          r = {None: 'http://ns.infrae.com/foo', 'p': 'http://test/'}
    2448          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2449          self.assertEqual(None, e.prefix)
    2450          self.assertEqual('{http://ns.infrae.com/foo}bar', e.tag)
    2451          self.assertEqual(
    2452              _bytes('<bar xmlns="http://ns.infrae.com/foo" xmlns:p="http://test/"></bar>'),
    2453              self._writeElement(e))
    2454
    2455 -    def test_namespaces_default_and_attr(self):
    2456          etree = self.etree
    2457
    2458          r = {None: 'http://ns.infrae.com/foo',
    2459               'hoi': 'http://ns.infrae.com/hoi'}
    2460          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2461          e.set('{http://ns.infrae.com/hoi}test', 'value')
    2462          self.assertEqual(
    2463              _bytes('<bar xmlns="http://ns.infrae.com/foo" xmlns:hoi="http://ns.infrae.com/hoi" hoi:test="value"></bar>'),
    2464              self._writeElement(e))
    2465
    2466 -    def test_attribute_keeps_namespace_prefix_on_merge(self):
    2467          etree = self.etree
    2468
    2469          root = etree.Element('{http://test/ns}root',
    2470                               nsmap={None: 'http://test/ns'})
    2471          sub = etree.Element('{http://test/ns}sub',
    2472                              nsmap={'test': 'http://test/ns'})
    2473
    2474          sub.attrib['{http://test/ns}attr'] = 'value'
    2475          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2476          self.assertEqual(
    2477              _bytes('<test:sub xmlns:test="http://test/ns" test:attr="value"/>'),
    2478              etree.tostring(sub))
    2479
    2480          root.append(sub)
    2481          self.assertEqual(
    2482              _bytes('<root xmlns="http://test/ns">'
    2483                     '<sub xmlns:test="http://test/ns" test:attr="value"/>'
    2484                     '</root>'),
    2485              etree.tostring(root))
    2486
    2487 -    def test_attribute_keeps_namespace_prefix_on_merge_with_nons(self):
    2488          etree = self.etree
    2489
    2490          root = etree.Element('root')
    2491          sub = etree.Element('{http://test/ns}sub',
    2492                              nsmap={'test': 'http://test/ns'})
    2493
    2494          sub.attrib['{http://test/ns}attr'] = 'value'
    2495          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2496          self.assertEqual(
    2497              _bytes('<test:sub xmlns:test="http://test/ns" test:attr="value"/>'),
    2498              etree.tostring(sub))
    2499
    2500          root.append(sub)
    2501          self.assertEqual(
    2502              _bytes('<root>'
    2503                     '<test:sub xmlns:test="http://test/ns" test:attr="value"/>'
    2504                     '</root>'),
    2505              etree.tostring(root))
    2506
    2507 -    def test_attribute_gets_namespace_prefix_on_merge_with_nons(self):
    2508          etree = self.etree
    2509
    2510          root = etree.Element('root')
    2511          sub = etree.Element('{http://test/ns}sub',
    2512                              nsmap={None: 'http://test/ns'})
    2513
    2514          sub.attrib['{http://test/ns}attr'] = 'value'
    2515          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2516          self.assertEqual(
    2517              _bytes('<sub xmlns="http://test/ns" '
    2518                     'xmlns:ns0="http://test/ns" ns0:attr="value"/>'),
    2519              etree.tostring(sub))
    2520
    2521          root.append(sub)
    2522          self.assertEqual(
    2523              _bytes('<root>'
    2524                     '<sub xmlns="http://test/ns"'
    2525                     ' xmlns:ns0="http://test/ns" ns0:attr="value"/>'
    2526                     '</root>'),
    2527              etree.tostring(root))
    2528
    2529 -    def test_attribute_gets_namespace_prefix_on_merge(self):
    2530          etree = self.etree
    2531
    2532          root = etree.Element('{http://test/ns}root',
    2533                               nsmap={'test': 'http://test/ns',
    2534                                      None: 'http://test/ns'})
    2535          sub = etree.Element('{http://test/ns}sub',
    2536                              nsmap={None: 'http://test/ns'})
    2537
    2538          sub.attrib['{http://test/ns}attr'] = 'value'
    2539          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2540          self.assertEqual(
    2541              _bytes('<sub xmlns="http://test/ns" '
    2542                     'xmlns:ns0="http://test/ns" ns0:attr="value"/>'),
    2543              etree.tostring(sub))
    2544
    2545          root.append(sub)
    2546          self.assertEqual(
    2547              _bytes('<test:root xmlns:test="http://test/ns" xmlns="http://test/ns">'
    2548                     '<test:sub test:attr="value"/>'
    2549                     '</test:root>'),
    2550              etree.tostring(root))
    2551
    2552 -    def test_namespaces_elementtree(self):
    2553          etree = self.etree
    2554          r = {None: 'http://ns.infrae.com/foo',
    2555               'hoi': 'http://ns.infrae.com/hoi'}
    2556          e = etree.Element('{http://ns.infrae.com/foo}z', nsmap=r)
    2557          tree = etree.ElementTree(element=e)
    2558          etree.SubElement(e, '{http://ns.infrae.com/hoi}x')
    2559          self.assertEqual(
    2560              _bytes('<z xmlns="http://ns.infrae.com/foo" xmlns:hoi="http://ns.infrae.com/hoi"><hoi:x></hoi:x></z>'),
    2561              self._writeElement(e))
    2562
    2563 -    def test_namespaces_default_copy_element(self):
    2564          etree = self.etree
    2565
    2566          r = {None: 'http://ns.infrae.com/foo'}
    2567          e1 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2568          e2 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2569
    2570          e1.append(e2)
    2571
    2572          self.assertEqual(
    2573              None,
    2574              e1.prefix)
    2575          self.assertEqual(
    2576              None,
    2577              e1[0].prefix)
    2578          self.assertEqual(
    2579              '{http://ns.infrae.com/foo}bar',
    2580              e1.tag)
    2581          self.assertEqual(
    2582              '{http://ns.infrae.com/foo}bar',
    2583              e1[0].tag)
    2584
    2585 -    def test_namespaces_copy_element(self):
    2586          etree = self.etree
    2587
    2588          r = {None: 'http://ns.infrae.com/BAR'}
    2589          e1 = etree.Element('{http://ns.infrae.com/BAR}bar', nsmap=r)
    2590          e2 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2591
    2592          e1.append(e2)
    2593
    2594          self.assertEqual(
    2595              None,
    2596              e1.prefix)
    2597          self.assertNotEqual(
    2598              None,
    2599              e2.prefix)
    2600          self.assertEqual(
    2601              '{http://ns.infrae.com/BAR}bar',
    2602              e1.tag)
    2603          self.assertEqual(
    2604              '{http://ns.infrae.com/foo}bar',
    2605              e2.tag)
    2606
    2607 -    def test_namespaces_reuse_after_move(self):
    2608          ns_href = "http://a.b.c"
    2609          one = self.etree.fromstring(
    2610              _bytes('<foo><bar xmlns:ns="%s"><ns:baz/></bar></foo>' % ns_href))
    2611          baz = one[0][0]
    2612
    2613          two = self.etree.fromstring(
    2614              _bytes('<root xmlns:ns="%s"/>' % ns_href))
    2615          two.append(baz)
    2616          del one # make sure the source document is deallocated
    2617
    2618          self.assertEqual('{%s}baz' % ns_href, baz.tag)
    2619          self.assertEqual(
    2620              _bytes('<root xmlns:ns="%s"><ns:baz/></root>' % ns_href),
    2621              self.etree.tostring(two))
    2622
    2623 -    def test_namespace_cleanup(self):
    2624          xml = _bytes(
    2625              '<foo xmlns="F" xmlns:x="x">'
    2626              '<bar xmlns:ns="NS" xmlns:b="b" xmlns="B">'
    2627              '<ns:baz/>'
    2628              '</bar></foo>'
    2629          )
    2630          root = self.etree.fromstring(xml)
    2631          self.assertEqual(xml, self.etree.tostring(root))
    2632          self.etree.cleanup_namespaces(root)
    2633          self.assertEqual(
    2634              _bytes('<foo xmlns="F"><bar xmlns:ns="NS" xmlns="B"><ns:baz/></bar></foo>'),
    2635              self.etree.tostring(root))
    2636
    2637 -    def test_namespace_cleanup_attributes(self):
    2638          xml = _bytes(
    2639              '<foo xmlns="F" xmlns:x="X" xmlns:a="A">'
    2640              '<bar xmlns:ns="NS" xmlns:b="b" xmlns="B">'
    2641              '<ns:baz a:test="attr"/>'
    2642              '</bar></foo>'
    2643          )
    2644          root = self.etree.fromstring(xml)
    2645          self.assertEqual(xml, self.etree.tostring(root))
    2646          self.etree.cleanup_namespaces(root)
    2647          self.assertEqual(
    2648              _bytes('<foo xmlns="F" xmlns:a="A">'
    2649                     '<bar xmlns:ns="NS" xmlns="B">'
    2650                     '<ns:baz a:test="attr"/>'
    2651                     '</bar></foo>'),
    2652              self.etree.tostring(root))
    2653
    2654 -    def test_namespace_cleanup_many(self):
    2655          xml = ('<n12:foo ' +
    2656                 ' '.join('xmlns:n{n}="NS{n}"'.format(n=i) for i in range(100)) +
    2657                 '><n68:a/></n12:foo>').encode('utf8')
    2658          root = self.etree.fromstring(xml)
    2659          self.assertEqual(xml, self.etree.tostring(root))
    2660          self.etree.cleanup_namespaces(root)
    2661          self.assertEqual(
    2662              b'<n12:foo xmlns:n12="NS12" xmlns:n68="NS68"><n68:a/></n12:foo>',
    2663              self.etree.tostring(root))
    2664
    2665 -    def test_namespace_cleanup_deep(self):
    2666          xml = ('<root>' +
    2667                 ''.join('<a xmlns:n{n}="NS{n}">'.format(n=i) for i in range(100)) +
    2668                 '<n64:x/>' + '</a>'*100 + '</root>').encode('utf8')
    2669          root = self.etree.fromstring(xml)
    2670          self.assertEqual(xml, self.etree.tostring(root))
    2671          self.etree.cleanup_namespaces(root)
    2672          self.assertEqual(
    2673              b'<root>' + b'<a>'*64 + b'<a xmlns:n64="NS64">' + b'<a>'*35 +
    2674              b'<n64:x/>' + b'</a>'*100 + b'</root>',
    2675              self.etree.tostring(root))
    2676
    2677 -    def test_namespace_cleanup_deep_to_top(self):
    2678          xml = ('<root>' +
    2679                 ''.join('<a xmlns:n{n}="NS{n}">'.format(n=i) for i in range(100)) +
    2680                 '<n64:x xmlns:a="A" a:attr="X"/>' +
    2681                 '</a>'*100 +
    2682                 '</root>').encode('utf8')
    2683          root = self.etree.fromstring(xml)
    2684          self.assertEqual(xml, self.etree.tostring(root))
    2685          self.etree.cleanup_namespaces(root, top_nsmap={'n64': 'NS64'})
    2686          self.assertEqual(
    2687              b'<root xmlns:n64="NS64">' + b'<a>'*100 +
    2688              b'<n64:x xmlns:a="A" a:attr="X"/>' + b'</a>'*100 + b'</root>',
    2689              self.etree.tostring(root))
    2690
    2691 -    def test_namespace_cleanup_keep_prefixes(self):
    2692          xml = ('<root xmlns:n64="NS64" xmlns:foo="FOO" xmlns:unused1="UNUSED" xmlns:no="NO">'
    2693                 '<a xmlns:unused2="UNUSED"><n64:x xmlns:a="A" a:attr="X"/></a>'
    2694                 '<foo>foo:bar</foo>'
    2695                 '</root>').encode('utf8')
    2696          root = self.etree.fromstring(xml)
    2697          self.assertEqual(xml, self.etree.tostring(root))
    2698          self.etree.cleanup_namespaces(root, keep_ns_prefixes=['foo'])
    2699          self.assertEqual(
    2700              b'<root xmlns:n64="NS64" xmlns:foo="FOO">'
    2701              b'<a><n64:x xmlns:a="A" a:attr="X"/></a>'
    2702              b'<foo>foo:bar</foo>'
    2703              b'</root>',
    2704              self.etree.tostring(root))
    2705
    2706 -    def test_namespace_cleanup_keep_prefixes_top(self):
    2707          xml = ('<root xmlns:n64="NS64" xmlns:unused1="UNUSED" xmlns:no="NO">'
    2708                 '<sub xmlns:foo="FOO">'
    2709                 '<a xmlns:unused2="UNUSED"><n64:x xmlns:a="A" a:attr="X"/></a>'
    2710                 '<foo>foo:bar</foo>'
    2711                 '</sub>'
    2712                 '</root>').encode('utf8')
    2713          root = self.etree.fromstring(xml)
    2714          self.assertEqual(xml, self.etree.tostring(root))
    2715          self.etree.cleanup_namespaces(
    2716              root,
    2717              top_nsmap={'foo': 'FOO', 'unused1': 'UNUSED'},
    2718              keep_ns_prefixes=['foo'])
    2719          self.assertEqual(
    2720              b'<root xmlns:n64="NS64" xmlns:foo="FOO">'
    2721              b'<sub>'
    2722              b'<a><n64:x xmlns:a="A" a:attr="X"/></a>'
    2723              b'<foo>foo:bar</foo>'
    2724              b'</sub>'
    2725              b'</root>',
    2726              self.etree.tostring(root))
    2727
    2728 -    def test_element_nsmap(self):
    2729          etree = self.etree
    2730
    2731          r = {None: 'http://ns.infrae.com/foo',
    2732               'hoi': 'http://ns.infrae.com/hoi'}
    2733          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2734          self.assertEqual(
    2735              r,
    2736              e.nsmap)
    2737
    2738 -    def test_subelement_nsmap(self):
    2739          etree = self.etree
    2740
    2741          re = {None: 'http://ns.infrae.com/foo',
    2742               'hoi': 'http://ns.infrae.com/hoi'}
    2743          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=re)
    2744
    2745          rs = {None: 'http://ns.infrae.com/honk',
    2746               'top': 'http://ns.infrae.com/top'}
    2747          s = etree.SubElement(e, '{http://ns.infrae.com/honk}bar', nsmap=rs)
    2748
    2749          r = re.copy()
    2750          r.update(rs)
    2751          self.assertEqual(re, e.nsmap)
    2752          self.assertEqual(r,  s.nsmap)
    2753
    2754 -    def test_html_prefix_nsmap(self):
    2755          etree = self.etree
    2756          el = etree.HTML('<hha:page-description>aa</hha:page-description>').find('.//page-description')
    2757          self.assertEqual({'hha': None}, el.nsmap)
    2758
    2759 -    def test_getiterator_filter_multiple(self):
    2760          Element = self.etree.Element
    2761          SubElement = self.etree.SubElement
    2762
    2763          a = Element('a')
    2764          b = SubElement(a, 'b')
    2765          c = SubElement(a, 'c')
    2766          d = SubElement(b, 'd')
    2767          e = SubElement(c, 'e')
    2768          f = SubElement(c, 'f')
    2769
    2770          self.assertEqual(
    2771              [a, b],
    2772                 list(a.getiterator('a', 'b')))
    2773          self.assertEqual(
    2774              [],
    2775                list(a.getiterator('x', 'y')))
    2776          self.assertEqual(
    2777              [a, f],
    2778                list(a.getiterator('f', 'a')))
    2779          self.assertEqual(
    2780              [c, e, f],
    2781                 list(c.getiterator('c', '*', 'a')))
    2782          self.assertEqual(
    2783              [],
    2784                    list(a.getiterator( (), () )))
    2785
    2786 -    def test_getiterator_filter_multiple_tuple(self):
    2787          Element = self.etree.Element
    2788          SubElement = self.etree.SubElement
    2789
    2790          a = Element('a')
    2791          b = SubElement(a, 'b')
    2792          c = SubElement(a, 'c')
    2793          d = SubElement(b, 'd')
    2794          e = SubElement(c, 'e')
    2795          f = SubElement(c, 'f')
    2796
    2797          self.assertEqual(
    2798              [a, b],
    2799                    list(a.getiterator( ('a', 'b') )))
    2800          self.assertEqual(
    2801              [],
    2802                list(a.getiterator( ('x', 'y') )))
    2803          self.assertEqual(
    2804              [a, f],
    2805                    list(a.getiterator( ('f', 'a') )))
    2806          self.assertEqual(
    2807              [c, e, f],
    2808                       list(c.getiterator( ('c', '*', 'a') )))
    2809          self.assertEqual(
    2810              [],
    2811                list(a.getiterator( () )))
    2812
    2813 -    def test_getiterator_filter_namespace(self):
    2814          Element = self.etree.Element
    2815          SubElement = self.etree.SubElement
    2816
    2817          a = Element('{a}a')
    2818          b = SubElement(a, '{a}b')
    2819          c = SubElement(a, '{a}c')
    2820          d = SubElement(b, '{b}d')
    2821          e = SubElement(c, '{a}e')
    2822          f = SubElement(c, '{b}f')
    2823          g = SubElement(c, 'g')
    2824
    2825          self.assertEqual(
    2826              [a],
    2827              list(a.getiterator('{a}a')))
    2828          self.assertEqual(
    2829              [],
    2830              list(a.getiterator('{b}a')))
    2831          self.assertEqual(
    2832              [],
    2833              list(a.getiterator('a')))
    2834          self.assertEqual(
    2835              [a,b,d,c,e,f,g],
    2836              list(a.getiterator('*')))
    2837          self.assertEqual(
    2838              [f],
    2839              list(c.getiterator('{b}*')))
    2840          self.assertEqual(
    2841              [d, f],
    2842              list(a.getiterator('{b}*')))
    2843          self.assertEqual(
    2844              [g],
    2845              list(a.getiterator('g')))
    2846          self.assertEqual(
    2847              [g],
    2848              list(a.getiterator('{}g')))
    2849          self.assertEqual(
    2850              [g],
    2851              list(a.getiterator('{}*')))
    2852
    2853 -    def test_getiterator_filter_local_name(self):
    2854          Element = self.etree.Element
    2855          SubElement = self.etree.SubElement
    2856
    2857          a = Element('{a}a')
    2858          b = SubElement(a, '{nsA}b')
    2859          c = SubElement(b, '{nsB}b')
    2860          d = SubElement(a, 'b')
    2861          e = SubElement(a, '{nsA}e')
    2862          f = SubElement(e, '{nsB}e')
    2863          g = SubElement(e, 'e')
    2864
    2865          self.assertEqual(
    2866              [b, c, d],
    2867              list(a.getiterator('{*}b')))
    2868          self.assertEqual(
    2869              [e, f, g],
    2870              list(a.getiterator('{*}e')))
    2871          self.assertEqual(
    2872              [a, b, c, d, e, f, g],
    2873              list(a.getiterator('{*}*')))
    2874
    2875 -    def test_getiterator_filter_entities(self):
    2876          Element = self.etree.Element
    2877          Entity = self.etree.Entity
    2878          SubElement = self.etree.SubElement
    2879
    2880          a = Element('a')
    2881          b = SubElement(a, 'b')
    2882          entity_b = Entity("TEST-b")
    2883          b.append(entity_b)
    2884
    2885          self.assertEqual(
    2886              [entity_b],
    2887              list(a.getiterator(Entity)))
    2888
    2889          entity_a = Entity("TEST-a")
    2890          a.append(entity_a)
    2891
    2892          self.assertEqual(
    2893              [entity_b, entity_a],
    2894              list(a.getiterator(Entity)))
    2895
    2896          self.assertEqual(
    2897              [entity_b],
    2898              list(b.getiterator(Entity)))
    2899
    2900 -    def test_getiterator_filter_element(self):
    2901          Element = self.etree.Element
    2902          Comment = self.etree.Comment
    2903          PI = self.etree.PI
    2904          SubElement = self.etree.SubElement
    2905
    2906          a = Element('a')
    2907          b = SubElement(a, 'b')
    2908          a.append(Comment("test"))
    2909          a.append(PI("pi", "content"))
    2910          c = SubElement(a, 'c')
    2911
    2912          self.assertEqual(
    2913              [a, b, c],
    2914              list(a.getiterator(Element)))
    2915
    2916 -    def test_getiterator_filter_all_comment_pi(self):
    2917          # ElementTree iterates over everything here
    2918          Element = self.etree.Element
    2919          Comment = self.etree.Comment
    2920          PI = self.etree.PI
    2921          SubElement = self.etree.SubElement
    2922
    2923          a = Element('a')
    2924          b = SubElement(a, 'b')
    2925          a.append(Comment("test"))
    2926          a.append(PI("pi", "content"))
    2927          c = SubElement(a, 'c')
    2928
    2929          self.assertEqual(
    2930              [a, b, c],
    2931              list(a.getiterator('*')))
    2932
    2933 -    def test_elementtree_getelementpath(self):
    2934          a  = etree.Element("a")
    2935          b  = etree.SubElement(a, "b")
    2936          c  = etree.SubElement(a, "c")
    2937          d1 = etree.SubElement(c, "d")
    2938          d2 = etree.SubElement(c, "d")
    2939          c.text = d1.text = 'TEXT'
    2940
    2941          tree = etree.ElementTree(a)
    2942          self.assertEqual('.', tree.getelementpath(a))
    2943          self.assertEqual('c/d[1]', tree.getelementpath(d1))
    2944          self.assertEqual('c/d[2]', tree.getelementpath(d2))
    2945
    2946          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    2947          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    2948
    2949          tree = etree.ElementTree(c)
    2950          self.assertEqual('.', tree.getelementpath(c))
    2951          self.assertEqual('d[2]', tree.getelementpath(d2))
    2952          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    2953
    2954          tree = etree.ElementTree(b)  # not a parent of a/c/d1/d2
    2955          self.assertEqual('.', tree.getelementpath(b))
    2956          self.assertRaises(ValueError, tree.getelementpath, a)
    2957          self.assertRaises(ValueError, tree.getelementpath, c)
    2958          self.assertRaises(ValueError, tree.getelementpath, d2)
    2959
    2960 -    def test_elementtree_getelementpath_ns(self):
    2961          a  = etree.Element("{http://ns1/}a")
    2962          b  = etree.SubElement(a, "{http://ns1/}b")
    2963          c  = etree.SubElement(a, "{http://ns1/}c")
    2964          d1 = etree.SubElement(c, "{http://ns1/}d")
    2965          d2 = etree.SubElement(c, "{http://ns2/}d")
    2966          d3 = etree.SubElement(c, "{http://ns1/}d")
    2967
    2968          tree = etree.ElementTree(a)
    2969          self.assertEqual('.', tree.getelementpath(a))
    2970          self.assertEqual('{http://ns1/}c/{http://ns1/}d[1]',
    2971                           tree.getelementpath(d1))
    2972          self.assertEqual('{http://ns1/}c/{http://ns2/}d',
    2973                           tree.getelementpath(d2))
    2974          self.assertEqual('{http://ns1/}c/{http://ns1/}d[2]',
    2975                           tree.getelementpath(d3))
    2976
    2977          self.assertEqual(a, tree.find(tree.getelementpath(a)))
    2978          self.assertEqual(b, tree.find(tree.getelementpath(b)))
    2979          self.assertEqual(c, tree.find(tree.getelementpath(c)))
    2980          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    2981          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    2982          self.assertEqual(d3, tree.find(tree.getelementpath(d3)))
    2983
    2984          tree = etree.ElementTree(c)
    2985          self.assertEqual('{http://ns1/}d[1]', tree.getelementpath(d1))
    2986          self.assertEqual('{http://ns2/}d', tree.getelementpath(d2))
    2987          self.assertEqual('{http://ns1/}d[2]', tree.getelementpath(d3))
    2988          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    2989          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    2990          self.assertEqual(d3, tree.find(tree.getelementpath(d3)))
    2991
    2992          tree = etree.ElementTree(b)  # not a parent of d1/d2
    2993          self.assertRaises(ValueError, tree.getelementpath, d1)
    2994          self.assertRaises(ValueError, tree.getelementpath, d2)
    2995
    2996 -    def test_elementtree_find_qname(self):
    2997          XML = self.etree.XML
    2998          ElementTree = self.etree.ElementTree
    2999          QName = self.etree.QName
    3000          tree = ElementTree(XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')))
    3001          self.assertEqual(tree.find(QName("c")), tree.getroot()[2])
    3002
    3003 -    def test_elementtree_findall_qname(self):
    3004          XML = self.etree.XML
    3005          ElementTree = self.etree.ElementTree
    3006          QName = self.etree.QName
    3007          tree = ElementTree(XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')))
    3008          self.assertEqual(len(list(tree.findall(QName("c")))), 1)
    3009
    3010 -    def test_elementtree_findall_ns_qname(self):
    3011          XML = self.etree.XML
    3012          ElementTree = self.etree.ElementTree
    3013          QName = self.etree.QName
    3014          tree = ElementTree(XML(
    3015                  _bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>')))
    3016          self.assertEqual(len(list(tree.findall(QName("b")))), 2)
    3017          self.assertEqual(len(list(tree.findall(QName("X", "b")))), 1)
    3018
    3019 -    def test_findall_ns(self):
    3020          XML = self.etree.XML
    3021          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>'))
    3022          self.assertEqual(len(root.findall(".//{X}b")), 2)
    3023          self.assertEqual(len(root.findall(".//{X}*")), 2)
    3024          self.assertEqual(len(root.findall(".//b")), 3)
    3025
    3026 -    def test_findall_different_nsmaps(self):
    3027          XML = self.etree.XML
    3028          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><y:b/></a>'))
    3029          nsmap = {'xx': 'X'}
    3030          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
    3031          self.assertEqual(len(root.findall(".//xx:*", namespaces=nsmap)), 2)
    3032          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
    3033          nsmap = {'xx': 'Y'}
    3034          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 1)
    3035          self.assertEqual(len(root.findall(".//xx:*", namespaces=nsmap)), 1)
    3036          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
    3037
    3038 -    def test_findall_empty_prefix(self):
    3039          XML = self.etree.XML
    3040          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><y:b/></a>'))
    3041          nsmap = {'xx': 'X'}
    3042          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
    3043          nsmap = {'xx': 'X', None: 'Y'}
    3044          self.assertRaises(ValueError, root.findall, ".//xx:b", namespaces=nsmap)
    3045          nsmap = {'xx': 'X', '': 'Y'}
    3046          self.assertRaises(ValueError, root.findall, ".//xx:b", namespaces=nsmap)
    3047
    3048 -    def test_findall_syntax_error(self):
    3049          XML = self.etree.XML
    3050          root = XML(_bytes('<a><b><c/></b><b/><c><b/><b/></c><b/></a>'))
    3051          self.assertRaises(SyntaxError, root.findall, '')
    3052          self.assertRaises(SyntaxError, root.findall, '//')  # absolute path on Element
    3053          self.assertRaises(SyntaxError, root.findall, './//')
    3054
    3055 -    def test_index(self):
    3056          etree = self.etree
    3057          e = etree.Element('foo')
    3058          for i in range(10):
    3059              etree.SubElement(e, 'a%s' % i)
    3060          for i in range(10):
    3061              self.assertEqual(
    3062                  i,
    3063                  e.index(e[i]))
    3064          self.assertEqual(
    3065              3, e.index(e[3], 3))
    3066          self.assertRaises(
    3067              ValueError, e.index, e[3], 4)
    3068          self.assertRaises(
    3069              ValueError, e.index, e[3], 0, 2)
    3070          self.assertRaises(
    3071              ValueError, e.index, e[8], 0, -3)
    3072          self.assertRaises(
    3073              ValueError, e.index, e[8], -5, -3)
    3074          self.assertEqual(
    3075              8, e.index(e[8], 0, -1))
    3076          self.assertEqual(
    3077              8, e.index(e[8], -12, -1))
    3078          self.assertEqual(
    3079              0, e.index(e[0], -12, -1))
    3080
    3081 -    def test_replace(self):
    3082          etree = self.etree
    3083          e = etree.Element('foo')
    3084          for i in range(10):
    3085              el = etree.SubElement(e, 'a%s' % i)
    3086              el.text = "text%d" % i
    3087              el.tail = "tail%d" % i
    3088
    3089          child0 = e[0]
    3090          child1 = e[1]
    3091          child2 = e[2]
    3092
    3093          e.replace(e[0], e[1])
    3094          self.assertEqual(
    3095              9, len(e))
    3096          self.assertEqual(
    3097              child1, e[0])
    3098          self.assertEqual(
    3099              child1.text, "text1")
    3100          self.assertEqual(
    3101              child1.tail, "tail1")
    3102          self.assertEqual(
    3103              child0.tail, "tail0")
    3104          self.assertEqual(
    3105              child2, e[1])
    3106
    3107          e.replace(e[-1], e[0])
    3108          self.assertEqual(
    3109              child1, e[-1])
    3110          self.assertEqual(
    3111              child1.text, "text1")
    3112          self.assertEqual(
    3113              child1.tail, "tail1")
    3114          self.assertEqual(
    3115              child2, e[0])
    3116
    3117 -    def test_replace_new(self):
    3118          etree = self.etree
    3119          e = etree.Element('foo')
    3120          for i in range(10):
    3121              etree.SubElement(e, 'a%s' % i)
    3122
    3123          new_element = etree.Element("test")
    3124          new_element.text = "TESTTEXT"
    3125          new_element.tail = "TESTTAIL"
    3126          child1 = e[1]
    3127          e.replace(e[0], new_element)
    3128          self.assertEqual(
    3129              new_element, e[0])
    3130          self.assertEqual(
    3131              "TESTTEXT",
    3132              e[0].text)
    3133          self.assertEqual(
    3134              "TESTTAIL",
    3135              e[0].tail)
    3136          self.assertEqual(
    3137              child1, e[1])
    3138
    3139 -    def test_setslice_all_empty_reversed(self):
    3140          Element = self.etree.Element
    3141          SubElement = self.etree.SubElement
    3142
    3143          a = Element('a')
    3144
    3145          e = Element('e')
    3146          f = Element('f')
    3147          g = Element('g')
    3148
    3149          s = [e, f, g]
    3150          a[::-1] = s
    3151          self.assertEqual(
    3152              [g, f, e],
    3153              list(a))
    3154
    3155 -    def test_setslice_step(self):
    3156          Element = self.etree.Element
    3157          SubElement = self.etree.SubElement
    3158
    3159          a = Element('a')
    3160          b = SubElement(a, 'b')
    3161          c = SubElement(a, 'c')
    3162          d = SubElement(a, 'd')
    3163          e = SubElement(a, 'e')
    3164
    3165          x = Element('x')
    3166          y = Element('y')
    3167
    3168          a[1::2] = [x, y]
    3169          self.assertEqual(
    3170              [b, x, d, y],
    3171              list(a))
    3172
    3173 -    def test_setslice_step_negative(self):
    3174          Element = self.etree.Element
    3175          SubElement = self.etree.SubElement
    3176
    3177          a = Element('a')
    3178          b = SubElement(a, 'b')
    3179          c = SubElement(a, 'c')
    3180          d = SubElement(a, 'd')
    3181          e = SubElement(a, 'e')
    3182
    3183          x = Element('x')
    3184          y = Element('y')
    3185
    3186          a[1::-1] = [x, y]
    3187          self.assertEqual(
    3188              [y, x, d, e],
    3189              list(a))
    3190
    3191 -    def test_setslice_step_negative2(self):
    3192          Element = self.etree.Element
    3193          SubElement = self.etree.SubElement
    3194
    3195          a = Element('a')
    3196          b = SubElement(a, 'b')
    3197          c = SubElement(a, 'c')
    3198          d = SubElement(a, 'd')
    3199          e = SubElement(a, 'e')
    3200
    3201          x = Element('x')
    3202          y = Element('y')
    3203
    3204          a[::-2] = [x, y]
    3205          self.assertEqual(
    3206              [b, y, d, x],
    3207              list(a))
    3208
    3209 -    def test_setslice_step_overrun(self):
    3210          Element = self.etree.Element
    3211          SubElement = self.etree.SubElement
    3212          try:
    3213              slice
    3214          except NameError:
    3215              print("slice() not found")
    3216              return
    3217
    3218          a = Element('a')
    3219          b = SubElement(a, 'b')
    3220          c = SubElement(a, 'c')
    3221          d = SubElement(a, 'd')
    3222          e = SubElement(a, 'e')
    3223
    3224          x = Element('x')
    3225          y = Element('y')
    3226          z = Element('z')
    3227
    3228          self.assertRaises(
    3229              ValueError,
    3230              operator.setitem, a, slice(1,None,2), [x, y, z])
    3231
    3232          self.assertEqual(
    3233              [b, c, d, e],
    3234              list(a))
    3235
    3236 -    def test_sourceline_XML(self):
    3237          XML = self.etree.XML
    3238          root = XML(_bytes('''<?xml version="1.0"?>
    3239          <root><test>
    3240
    3241          <bla/></test>
    3242          </root>
    3243          '''))
    3244
    3245          self.assertEqual(
    3246              [2, 2, 4],
    3247              [ el.sourceline for el in root.getiterator() ])
    3248
    3249 -    def test_large_sourceline_XML(self):
    3250          XML = self.etree.XML
    3251          root = XML(_bytes(
    3252              '<?xml version="1.0"?>\n'
    3253              '<root>' + '\n' * 65536 +
    3254              '<p>' + '\n' * 65536 + '</p>\n' +
    3255              '<br/>\n'
    3256              '</root>'))
    3257
    3258          if self.etree.LIBXML_VERSION >= (2, 9):
    3259              expected = [2, 131074, 131076]
    3260          else:
    3261              expected = [2, 65535, 65535]
    3262
    3263          self.assertEqual(expected, [el.sourceline for el in root.iter()])
    3264
    3265 -    def test_sourceline_parse(self):
    3266          parse = self.etree.parse
    3267          tree = parse(fileInTestDir('include/test_xinclude.xml'))
    3268
    3269          self.assertEqual(
    3270              [1, 2, 3],
    3271              [ el.sourceline for el in tree.getiterator() ])
    3272
    3273 -    def test_sourceline_iterparse_end(self):
    3274          iterparse = self.etree.iterparse
    3275          lines = [ el.sourceline for (event, el) in
    3276                    iterparse(fileInTestDir('include/test_xinclude.xml')) ]
    3277
    3278          self.assertEqual(
    3279              [2, 3, 1],
    3280              lines)
    3281
    3282 -    def test_sourceline_iterparse_start(self):
    3283          iterparse = self.etree.iterparse
    3284          lines = [ el.sourceline for (event, el) in
    3285                    iterparse(fileInTestDir('include/test_xinclude.xml'),
    3286                              events=("start",)) ]
    3287
    3288          self.assertEqual(
    3289              [1, 2, 3],
    3290              lines)
    3291
    3292 -    def test_sourceline_element(self):
    3293          Element = self.etree.Element
    3294          SubElement = self.etree.SubElement
    3295          el = Element("test")
    3296          self.assertEqual(None, el.sourceline)
    3297
    3298          child = SubElement(el, "test")
    3299          self.assertEqual(None, el.sourceline)
    3300          self.assertEqual(None, child.sourceline)
    3301
    3302 -    def test_XML_base_url_docinfo(self):
    3303          etree = self.etree
    3304          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3305          docinfo = root.getroottree().docinfo
    3306          self.assertEqual(docinfo.URL, "http://no/such/url")
    3307
    3308 -    def test_XML_set_base_url_docinfo(self):
    3309          etree = self.etree
    3310          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3311          docinfo = root.getroottree().docinfo
    3312          self.assertEqual(docinfo.URL, "http://no/such/url")
    3313          docinfo.URL = "https://secret/url"
    3314          self.assertEqual(docinfo.URL, "https://secret/url")
    3315
    3316 -    def test_parse_stringio_base_url(self):
    3317          etree = self.etree
    3318          tree = etree.parse(BytesIO("<root/>"), base_url="http://no/such/url")
    3319          docinfo = tree.docinfo
    3320          self.assertEqual(docinfo.URL, "http://no/such/url")
    3321
    3322 -    def test_parse_base_url_docinfo(self):
    3323          etree = self.etree
    3324          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    3325                             base_url="http://no/such/url")
    3326          docinfo = tree.docinfo
    3327          self.assertEqual(docinfo.URL, "http://no/such/url")
    3328
    3329 -    def test_HTML_base_url_docinfo(self):
    3330          etree = self.etree
    3331          root = etree.HTML(_bytes("<html/>"), base_url="http://no/such/url")
    3332          docinfo = root.getroottree().docinfo
    3333          self.assertEqual(docinfo.URL, "http://no/such/url")
    3334
    3335 -    def test_docinfo_public(self):
    3336          etree = self.etree
    3337          xml_header = '<?xml version="1.0" encoding="ascii"?>'
    3338          pub_id = "-//W3C//DTD XHTML 1.0 Transitional//EN"
    3339          sys_id = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    3340          doctype_string = '<!DOCTYPE html PUBLIC "%s" "%s">' % (pub_id, sys_id)
    3341
    3342          xml = _bytes(xml_header + doctype_string + '<html><body></body></html>')
    3343
    3344          tree = etree.parse(BytesIO(xml))
    3345          docinfo = tree.docinfo
    3346          self.assertEqual(docinfo.encoding,    "ascii")
    3347          self.assertEqual(docinfo.xml_version, "1.0")
    3348          self.assertEqual(docinfo.public_id,   pub_id)
    3349          self.assertEqual(docinfo.system_url,  sys_id)
    3350          self.assertEqual(docinfo.root_name,   'html')
    3351          self.assertEqual(docinfo.doctype, doctype_string)
    3352
    3353 -    def test_docinfo_system(self):
    3354          etree = self.etree
    3355          xml_header = '<?xml version="1.0" encoding="UTF-8"?>'
    3356          sys_id = "some.dtd"
    3357          doctype_string = '<!DOCTYPE html SYSTEM "%s">' % sys_id
    3358          xml = _bytes(xml_header + doctype_string + '<html><body></body></html>')
    3359
    3360          tree = etree.parse(BytesIO(xml))
    3361          docinfo = tree.docinfo
    3362          self.assertEqual(docinfo.encoding,    "UTF-8")
    3363          self.assertEqual(docinfo.xml_version, "1.0")
    3364          self.assertEqual(docinfo.public_id,   None)
    3365          self.assertEqual(docinfo.system_url,  sys_id)
    3366          self.assertEqual(docinfo.root_name,   'html')
    3367          self.assertEqual(docinfo.doctype, doctype_string)
    3368
    3369 -    def test_docinfo_empty(self):
    3370          etree = self.etree
    3371          xml = _bytes('<html><body></body></html>')
    3372          tree = etree.parse(BytesIO(xml))
    3373          docinfo = tree.docinfo
    3374          self.assertEqual(docinfo.encoding,    "UTF-8")
    3375          self.assertEqual(docinfo.xml_version, "1.0")
    3376          self.assertEqual(docinfo.public_id,   None)
    3377          self.assertEqual(docinfo.system_url,  None)
    3378          self.assertEqual(docinfo.root_name,   'html')
    3379          self.assertEqual(docinfo.doctype, '')
    3380
    3381 -    def test_docinfo_name_only(self):
    3382          etree = self.etree
    3383          xml = _bytes('<!DOCTYPE root><root></root>')
    3384          tree = etree.parse(BytesIO(xml))
    3385          docinfo = tree.docinfo
    3386          self.assertEqual(docinfo.encoding,    "UTF-8")
    3387          self.assertEqual(docinfo.xml_version, "1.0")
    3388          self.assertEqual(docinfo.public_id,   None)
    3389          self.assertEqual(docinfo.system_url,  None)
    3390          self.assertEqual(docinfo.root_name,   'root')
    3391          self.assertEqual(docinfo.doctype, '<!DOCTYPE root>')
    3392
    3393 -    def test_doctype_name_only_roundtrip(self):
    3394          etree = self.etree
    3395          xml = _bytes('<!DOCTYPE root>\n<root/>')
    3396          tree = etree.parse(BytesIO(xml))
    3397          self.assertEqual(xml, etree.tostring(tree))
    3398
    3399 -    def test_doctype_output_override(self):
    3400          etree = self.etree
    3401          pub_id = "-//W3C//DTD XHTML 1.0 Transitional//EN"
    3402          sys_id = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    3403          doctype_string = _bytes('<!DOCTYPE html PUBLIC "%s" "%s">' % (pub_id, sys_id))
    3404
    3405          xml = _bytes('<!DOCTYPE root>\n<root/>')
    3406          tree = etree.parse(BytesIO(xml))
    3407          self.assertEqual(xml.replace(_bytes('<!DOCTYPE root>'), doctype_string),
    3408                            etree.tostring(tree, doctype=doctype_string))
    3409
    3410 -    def test_xml_base(self):
    3411          etree = self.etree
    3412          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3413          self.assertEqual(root.base, "http://no/such/url")
    3414          self.assertEqual(
    3415              root.get('{http://www.w3.org/XML/1998/namespace}base'), None)
    3416          root.base = "https://secret/url"
    3417          self.assertEqual(root.base, "https://secret/url")
    3418          self.assertEqual(
    3419              root.get('{http://www.w3.org/XML/1998/namespace}base'),
    3420              "https://secret/url")
    3421
    3422 -    def test_xml_base_attribute(self):
    3423          etree = self.etree
    3424          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3425          self.assertEqual(root.base, "http://no/such/url")
    3426          self.assertEqual(
    3427              root.get('{http://www.w3.org/XML/1998/namespace}base'), None)
    3428          root.set('{http://www.w3.org/XML/1998/namespace}base',
    3429                   "https://secret/url")
    3430          self.assertEqual(root.base, "https://secret/url")
    3431          self.assertEqual(
    3432              root.get('{http://www.w3.org/XML/1998/namespace}base'),
    3433              "https://secret/url")
    3434
    3435 -    def test_html_base(self):
    3436          etree = self.etree
    3437          root = etree.HTML(_bytes("<html><body></body></html>"),
    3438                            base_url="http://no/such/url")
    3439          self.assertEqual(root.base, "http://no/such/url")
    3440
    3441 -    def test_html_base_tag(self):
    3442          etree = self.etree
    3443          root = etree.HTML(_bytes('<html><head><base href="http://no/such/url"></head></html>'))
    3444          self.assertEqual(root.base, "http://no/such/url")
    3445
    3446 -    def test_parse_fileobject_unicode(self):
    3447          # parse from a file object that returns unicode strings
    3448          f = LargeFileLikeUnicode()
    3449          tree = self.etree.parse(f)
    3450          root = tree.getroot()
    3451          self.assertTrue(root.tag.endswith('root'))
    3452
    3453 -    def test_dtd_io(self):
    3454          # check that DTDs that go in also go back out
    3455          xml = _bytes('''\
    3456          <!DOCTYPE test SYSTEM "test.dtd" [
    3457            <!ENTITY entity "tasty">
    3458            <!ELEMENT test (a)>
    3459            <!ELEMENT a (#PCDATA)>
    3460          ]>
    3461          <test><a>test-test</a></test>\
    3462          ''')
    3463          tree = self.etree.parse(BytesIO(xml))
    3464          self.assertEqual(self.etree.tostring(tree).replace(_bytes(" "), _bytes("")),
    3465                           xml.replace(_bytes(" "), _bytes("")))
    3466
    3467 -    def test_byte_zero(self):
    3468          Element = self.etree.Element
    3469
    3470          a = Element('a')
    3471          self.assertRaises(ValueError, setattr, a, "text", 'ha\0ho')
    3472          self.assertRaises(ValueError, setattr, a, "tail", 'ha\0ho')
    3473
    3474          self.assertRaises(ValueError, Element, 'ha\0ho')
    3475
    3476 -    def test_unicode_byte_zero(self):
    3477          Element = self.etree.Element
    3478
    3479          a = Element('a')
    3480          self.assertRaises(ValueError, setattr, a, "text",
    3481                            _str('ha\0ho'))
    3482          self.assertRaises(ValueError, setattr, a, "tail",
    3483                            _str('ha\0ho'))
    3484
    3485          self.assertRaises(ValueError, Element,
    3486                            _str('ha\0ho'))
    3487
    3488 -    def test_byte_invalid(self):
    3489          Element = self.etree.Element
    3490
    3491          a = Element('a')
    3492          self.assertRaises(ValueError, setattr, a, "text", 'ha\x07ho')
    3493          self.assertRaises(ValueError, setattr, a, "text", 'ha\x02ho')
    3494
    3495          self.assertRaises(ValueError, setattr, a, "tail", 'ha\x07ho')
    3496          self.assertRaises(ValueError, setattr, a, "tail", 'ha\x02ho')
    3497
    3498          self.assertRaises(ValueError, Element, 'ha\x07ho')
    3499          self.assertRaises(ValueError, Element, 'ha\x02ho')
    3500
    3501 -    def test_unicode_byte_invalid(self):
    3502          Element = self.etree.Element
    3503
    3504          a = Element('a')
    3505          self.assertRaises(ValueError, setattr, a, "text",
    3506                            _str('ha\x07ho'))
    3507          self.assertRaises(ValueError, setattr, a, "text",
    3508                            _str('ha\x02ho'))
    3509
    3510          self.assertRaises(ValueError, setattr, a, "tail",
    3511                            _str('ha\x07ho'))
    3512          self.assertRaises(ValueError, setattr, a, "tail",
    3513                            _str('ha\x02ho'))
    3514
    3515          self.assertRaises(ValueError, Element,
    3516                            _str('ha\x07ho'))
    3517          self.assertRaises(ValueError, Element,
    3518                            _str('ha\x02ho'))
    3519
    3520 -    def test_unicode_byte_invalid_sequence(self):
    3521          Element = self.etree.Element
    3522
    3523          a = Element('a')
    3524          self.assertRaises(ValueError, setattr, a, "text",
    3525                            _str('ha\u1234\x07ho'))
    3526          self.assertRaises(ValueError, setattr, a, "text",
    3527                            _str('ha\u1234\x02ho'))
    3528
    3529          self.assertRaises(ValueError, setattr, a, "tail",
    3530                            _str('ha\u1234\x07ho'))
    3531          self.assertRaises(ValueError, setattr, a, "tail",
    3532                            _str('ha\u1234\x02ho'))
    3533
    3534          self.assertRaises(ValueError, Element,
    3535                            _str('ha\u1234\x07ho'))
    3536          self.assertRaises(ValueError, Element,
    3537                            _str('ha\u1234\x02ho'))
    3538
    3539 -    def test_encoding_tostring_utf16(self):
    3540          # ElementTree fails to serialize this
    3541          tostring = self.etree.tostring
    3542          Element = self.etree.Element
    3543          SubElement = self.etree.SubElement
    3544
    3545          a = Element('a')
    3546          b = SubElement(a, 'b')
    3547          c = SubElement(a, 'c')
    3548
    3549          result = tostring(a, encoding='UTF-16')
    3550          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3551                            canonicalize(result))
    3552
    3553 -    def test_tostring_none(self):
    3554          # ElementTree raises an AssertionError here
    3555          tostring = self.etree.tostring
    3556          self.assertRaises(TypeError, self.etree.tostring, None)
    3557
    3558 -    def test_tostring_pretty(self):
    3559          tostring = self.etree.tostring
    3560          Element = self.etree.Element
    3561          SubElement = self.etree.SubElement
    3562
    3563          a = Element('a')
    3564          b = SubElement(a, 'b')
    3565          c = SubElement(a, 'c')
    3566
    3567          result = tostring(a)
    3568          self.assertEqual(result, _bytes("<a><b/><c/></a>"))
    3569
    3570          result = tostring(a, pretty_print=False)
    3571          self.assertEqual(result, _bytes("<a><b/><c/></a>"))
    3572
    3573          result = tostring(a, pretty_print=True)
    3574          self.assertEqual(result, _bytes("<a>\n  <b/>\n  <c/>\n</a>\n"))
    3575
    3576 -    def test_tostring_with_tail(self):
    3577          tostring = self.etree.tostring
    3578          Element = self.etree.Element
    3579          SubElement = self.etree.SubElement
    3580
    3581          a = Element('a')
    3582          a.tail = "aTAIL"
    3583          b = SubElement(a, 'b')
    3584          b.tail = "bTAIL"
    3585          c = SubElement(a, 'c')
    3586
    3587          result = tostring(a)
    3588          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>aTAIL"))
    3589
    3590          result = tostring(a, with_tail=False)
    3591          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>"))
    3592
    3593          result = tostring(a, with_tail=True)
    3594          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>aTAIL"))
    3595
    3596 -    def test_tostring_method_html_with_tail(self):
    3597          tostring = self.etree.tostring
    3598          html = self.etree.fromstring(
    3599              '<html><body>'
    3600              '<div><p>Some text<i>\r\n</i></p></div>\r\n'
    3601              '</body></html>',
    3602              parser=self.etree.HTMLParser())
    3603          self.assertEqual(html.tag, 'html')
    3604          div = html.find('.//div')
    3605          self.assertEqual(div.tail, '\r\n')
    3606          result = tostring(div, method='html')
    3607          self.assertEqual(
    3608              result,
    3609              _bytes("<div><p>Some text<i>\r\n</i></p></div>\r\n"))
    3610          result = tostring(div, method='html', with_tail=True)
    3611          self.assertEqual(
    3612              result,
    3613              _bytes("<div><p>Some text<i>\r\n</i></p></div>\r\n"))
    3614          result = tostring(div, method='html', with_tail=False)
    3615          self.assertEqual(
    3616              result,
    3617              _bytes("<div><p>Some text<i>\r\n</i></p></div>"))
    3618
    3619 -    def test_standalone(self):
    3620          tostring = self.etree.tostring
    3621          XML = self.etree.XML
    3622          ElementTree = self.etree.ElementTree
    3623          Element = self.etree.Element
    3624
    3625          tree = Element("root").getroottree()
    3626          self.assertEqual(None, tree.docinfo.standalone)
    3627
    3628          tree = XML(_bytes("<root/>")).getroottree()
    3629          self.assertEqual(None, tree.docinfo.standalone)
    3630
    3631          tree = XML(_bytes(
    3632              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"
    3633              )).getroottree()
    3634          self.assertEqual(True, tree.docinfo.standalone)
    3635
    3636          tree = XML(_bytes(
    3637              "<?xml version='1.0' encoding='ASCII' standalone='no'?>\n<root/>"
    3638              )).getroottree()
    3639          self.assertEqual(False, tree.docinfo.standalone)
    3640
    3641 -    def test_tostring_standalone(self):
    3642          tostring = self.etree.tostring
    3643          XML = self.etree.XML
    3644          ElementTree = self.etree.ElementTree
    3645
    3646          root = XML(_bytes("<root/>"))
    3647
    3648          tree = ElementTree(root)
    3649          self.assertEqual(None, tree.docinfo.standalone)
    3650
    3651          result = tostring(root, xml_declaration=True, encoding="ASCII")
    3652          self.assertEqual(result, _bytes(
    3653              "<?xml version='1.0' encoding='ASCII'?>\n<root/>"))
    3654
    3655          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3656                            standalone=True)
    3657          self.assertEqual(result, _bytes(
    3658              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"))
    3659
    3660          tree = ElementTree(XML(result))
    3661          self.assertEqual(True, tree.docinfo.standalone)
    3662
    3663          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3664                            standalone=False)
    3665          self.assertEqual(result, _bytes(
    3666              "<?xml version='1.0' encoding='ASCII' standalone='no'?>\n<root/>"))
    3667
    3668          tree = ElementTree(XML(result))
    3669          self.assertEqual(False, tree.docinfo.standalone)
    3670
    3671 -    def test_tostring_standalone_in_out(self):
    3672          tostring = self.etree.tostring
    3673          XML = self.etree.XML
    3674          ElementTree = self.etree.ElementTree
    3675
    3676          root = XML(_bytes(
    3677              "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n<root/>"))
    3678
    3679          tree = ElementTree(root)
    3680          self.assertEqual(True, tree.docinfo.standalone)
    3681
    3682          result = tostring(root, xml_declaration=True, encoding="ASCII")
    3683          self.assertEqual(result, _bytes(
    3684              "<?xml version='1.0' encoding='ASCII'?>\n<root/>"))
    3685
    3686          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3687                            standalone=True)
    3688          self.assertEqual(result, _bytes(
    3689              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"))
    3690
    3691 -    def test_tostring_method_text_encoding(self):
    3692          tostring = self.etree.tostring
    3693          Element = self.etree.Element
    3694          SubElement = self.etree.SubElement
    3695
    3696          a = Element('a')
    3697          a.text = "A"
    3698          a.tail = "tail"
    3699          b = SubElement(a, 'b')
    3700          b.text = "B"
    3701          b.tail = _str("Søk på nettet")
    3702          c = SubElement(a, 'c')
    3703          c.text = "C"
    3704
    3705          result = tostring(a, method="text", encoding="UTF-16")
    3706
    3707          self.assertEqual(_str('ABSøk på nettetCtail').encode("UTF-16"),
    3708                            result)
    3709
    3710 -    def test_tostring_method_text_unicode(self):
    3711          tostring = self.etree.tostring
    3712          Element = self.etree.Element
    3713          SubElement = self.etree.SubElement
    3714
    3715          a = Element('a')
    3716          a.text = _str('Søk på nettetA')
    3717          a.tail = "tail"
    3718          b = SubElement(a, 'b')
    3719          b.text = "B"
    3720          b.tail = _str('Søk på nettetB')
    3721          c = SubElement(a, 'c')
    3722          c.text = "C"
    3723
    3724          self.assertRaises(UnicodeEncodeError,
    3725                            tostring, a, method="text")
    3726
    3727          self.assertEqual(
    3728              _str('Søk på nettetABSøk på nettetBCtail').encode('utf-8'),
    3729              tostring(a, encoding="UTF-8", method="text"))
    3730
    3731 -    def test_tounicode(self):
    3732          tounicode = self.etree.tounicode
    3733          Element = self.etree.Element
    3734          SubElement = self.etree.SubElement
    3735
    3736          a = Element('a')
    3737          b = SubElement(a, 'b')
    3738          c = SubElement(a, 'c')
    3739
    3740          self.assertTrue(isinstance(tounicode(a), _unicode))
    3741          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3742                            canonicalize(tounicode(a)))
    3743
    3744 -    def test_tounicode_element(self):
    3745          tounicode = self.etree.tounicode
    3746          Element = self.etree.Element
    3747          SubElement = self.etree.SubElement
    3748
    3749          a = Element('a')
    3750          b = SubElement(a, 'b')
    3751          c = SubElement(a, 'c')
    3752          d = SubElement(c, 'd')
    3753          self.assertTrue(isinstance(tounicode(b), _unicode))
    3754          self.assertTrue(isinstance(tounicode(c), _unicode))
    3755          self.assertEqual(_bytes('<b></b>'),
    3756                            canonicalize(tounicode(b)))
    3757          self.assertEqual(_bytes('<c><d></d></c>'),
    3758                            canonicalize(tounicode(c)))
    3759
    3760 -    def test_tounicode_none(self):
    3761          tounicode = self.etree.tounicode
    3762          self.assertRaises(TypeError, self.etree.tounicode, None)
    3763
    3764 -    def test_tounicode_element_tail(self):
    3765          tounicode = self.etree.tounicode
    3766          Element = self.etree.Element
    3767          SubElement = self.etree.SubElement
    3768
    3769          a = Element('a')
    3770          b = SubElement(a, 'b')
    3771          c = SubElement(a, 'c')
    3772          d = SubElement(c, 'd')
    3773          b.tail = 'Foo'
    3774
    3775          self.assertTrue(isinstance(tounicode(b), _unicode))
    3776          self.assertTrue(tounicode(b) == '<b/>Foo' or
    3777                       tounicode(b) == '<b />Foo')
    3778
    3779 -    def test_tounicode_pretty(self):
    3780          tounicode = self.etree.tounicode
    3781          Element = self.etree.Element
    3782          SubElement = self.etree.SubElement
    3783
    3784          a = Element('a')
    3785          b = SubElement(a, 'b')
    3786          c = SubElement(a, 'c')
    3787
    3788          result = tounicode(a)
    3789          self.assertEqual(result, "<a><b/><c/></a>")
    3790
    3791          result = tounicode(a, pretty_print=False)
    3792          self.assertEqual(result, "<a><b/><c/></a>")
    3793
    3794          result = tounicode(a, pretty_print=True)
    3795          self.assertEqual(result, "<a>\n  <b/>\n  <c/>\n</a>\n")
    3796
    3797 -    def test_tostring_unicode(self):
    3798          tostring = self.etree.tostring
    3799          Element = self.etree.Element
    3800          SubElement = self.etree.SubElement
    3801
    3802          a = Element('a')
    3803          b = SubElement(a, 'b')
    3804          c = SubElement(a, 'c')
    3805
    3806          self.assertTrue(isinstance(tostring(a, encoding=_unicode), _unicode))
    3807          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3808                            canonicalize(tostring(a, encoding=_unicode)))
    3809
    3810 -    def test_tostring_unicode_element(self):
    3811          tostring = self.etree.tostring
    3812          Element = self.etree.Element
    3813          SubElement = self.etree.SubElement
    3814
    3815          a = Element('a')
    3816          b = SubElement(a, 'b')
    3817          c = SubElement(a, 'c')
    3818          d = SubElement(c, 'd')
    3819          self.assertTrue(isinstance(tostring(b, encoding=_unicode), _unicode))
    3820          self.assertTrue(isinstance(tostring(c, encoding=_unicode), _unicode))
    3821          self.assertEqual(_bytes('<b></b>'),
    3822                            canonicalize(tostring(b, encoding=_unicode)))
    3823          self.assertEqual(_bytes('<c><d></d></c>'),
    3824                            canonicalize(tostring(c, encoding=_unicode)))
    3825
    3826 -    def test_tostring_unicode_none(self):
    3827          tostring = self.etree.tostring
    3828          self.assertRaises(TypeError, self.etree.tostring,
    3829                            None, encoding=_unicode)
    3830
    3831 -    def test_tostring_unicode_element_tail(self):
    3832          tostring = self.etree.tostring
    3833          Element = self.etree.Element
    3834          SubElement = self.etree.SubElement
    3835
    3836          a = Element('a')
    3837          b = SubElement(a, 'b')
    3838          c = SubElement(a, 'c')
    3839          d = SubElement(c, 'd')
    3840          b.tail = 'Foo'
    3841
    3842          self.assertTrue(isinstance(tostring(b, encoding=_unicode), _unicode))
    3843          self.assertTrue(tostring(b, encoding=_unicode) == '<b/>Foo' or
    3844                       tostring(b, encoding=_unicode) == '<b />Foo')
    3845
    3846 -    def test_tostring_unicode_pretty(self):
    3847          tostring = self.etree.tostring
    3848          Element = self.etree.Element
    3849          SubElement = self.etree.SubElement
    3850
    3851          a = Element('a')
    3852          b = SubElement(a, 'b')
    3853          c = SubElement(a, 'c')
    3854
    3855          result = tostring(a, encoding=_unicode)
    3856          self.assertEqual(result, "<a><b/><c/></a>")
    3857
    3858          result = tostring(a, encoding=_unicode, pretty_print=False)
    3859          self.assertEqual(result, "<a><b/><c/></a>")
    3860
    3861          result = tostring(a, encoding=_unicode, pretty_print=True)
    3862          self.assertEqual(result, "<a>\n  <b/>\n  <c/>\n</a>\n")
    3863
    3864 -    def test_pypy_proxy_collect(self):
    3865          root = etree.Element('parent')
    3866          etree.SubElement(root, 'child')
    3867
    3868          self.assertEqual(len(root), 1)
    3869          self.assertEqual(root[0].tag, 'child')
    3870
    3871          # in PyPy, GC used to kill the Python proxy instance without cleanup
    3872          gc.collect()
    3873          self.assertEqual(len(root), 1)
    3874          self.assertEqual(root[0].tag, 'child')
    3875
    3876 -    def test_element_refcycle(self):
    3877          class SubEl(etree.ElementBase):
    3878              pass
    3879
    3880          el1 = SubEl()
    3881          el2 = SubEl()
    3882          self.assertEqual('SubEl', el1.tag)
    3883          self.assertEqual('SubEl', el2.tag)
    3884          el1.other = el2
    3885          el2.other = el1
    3886
    3887          del el1, el2
    3888          gc.collect()
    3889          # not really testing anything here, but it shouldn't crash
    3890
    3891 -    def test_proxy_collect_siblings(self):
    3892          root = etree.Element('parent')
    3893          c1 = etree.SubElement(root, 'child1')
    3894          c2 = etree.SubElement(root, 'child2')
    3895
    3896          root.remove(c1)
    3897          root.remove(c2)
    3898          c1.addnext(c2)
    3899          del c1
    3900          # trigger deallocation attempt of c1
    3901          c2.getprevious()
    3902          # make sure it wasn't deallocated
    3903          self.assertEqual('child1', c2.getprevious().tag)
    3904
    3905 -    def test_proxy_collect_siblings_text(self):
    3906          root = etree.Element('parent')
    3907          c1 = etree.SubElement(root, 'child1')
    3908          c2 = etree.SubElement(root, 'child2')
    3909
    3910          root.remove(c1)
    3911          root.remove(c2)
    3912          c1.addnext(c2)
    3913          c1.tail = 'abc'
    3914          c2.tail = 'xyz'
    3915          del c1
    3916          # trigger deallocation attempt of c1
    3917          c2.getprevious()
    3918          # make sure it wasn't deallocated
    3919          self.assertEqual('child1', c2.getprevious().tag)
    3920          self.assertEqual('abc', c2.getprevious().tail)
    3921
    3922      # helper methods
    3923
    3924 -    def _writeElement(self, element, encoding='us-ascii', compression=0):
    3925          """Write out element for comparison.
    3926          """
    3927          ElementTree = self.etree.ElementTree
    3928          f = BytesIO()
    3929          tree = ElementTree(element=element)
    3930          tree.write(f, encoding=encoding, compression=compression)
    3931          data = f.getvalue()
    3932          if compression:
    3933              data = zlib.decompress(data)
    3934          return canonicalize(data)
    3935
    3936
    3937 -class _XIncludeTestCase(HelperTestCase):
    3938 -    def test_xinclude_text(self):
    3939          filename = fileInTestDir('test_broken.xml')
    3940          root = etree.XML(_bytes('''\
    3941          <doc xmlns:xi="http://www.w3.org/2001/XInclude">
    3942            <xi:include href="%s" parse="text"/>
    3943          </doc>
    3944          ''' % path2url(filename)))
    3945          old_text = root.text
    3946          content = read_file(filename)
    3947          old_tail = root[0].tail
    3948
    3949          self.include( etree.ElementTree(root) )
    3950          self.assertEqual(old_text + content + old_tail,
    3951                            root.text)
    3952
    3953 -    def test_xinclude(self):
    3954          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'))
    3955          self.assertNotEqual(
    3956              'a',
    3957              tree.getroot()[1].tag)
    3958          # process xincludes
    3959          self.include( tree )
    3960          # check whether we find it replaced with included data
    3961          self.assertEqual(
    3962              'a',
    3963              tree.getroot()[1].tag)
    3964
    3965 -    def test_xinclude_resolver(self):
    3966          class res(etree.Resolver):
    3967              include_text = read_file(fileInTestDir('test.xml'))
    3968              called = {}
    3969              def resolve(self, url, id, context):
    3970                  if url.endswith(".dtd"):
    3971                      self.called["dtd"] = True
    3972                      return self.resolve_filename(
    3973                          fileInTestDir('test.dtd'), context)
    3974                  elif url.endswith("test_xinclude.xml"):
    3975                      self.called["input"] = True
    3976                      return None # delegate to default resolver
    3977                  else:
    3978                      self.called["include"] = True
    3979                      return self.resolve_string(self.include_text, context)
    3980
    3981          res_instance = res()
    3982          parser = etree.XMLParser(load_dtd = True)
    3983          parser.resolvers.add(res_instance)
    3984
    3985          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    3986                             parser = parser)
    3987
    3988          self.include(tree)
    3989
    3990          called = list(res_instance.called.items())
    3991          called.sort()
    3992          self.assertEqual(
    3993              [("dtd", True), ("include", True), ("input", True)],
    3994              called)
    3995
    3996 -    def test_xinclude_resolver_recursive(self):
    3997          data = textwrap.dedent('''
    3998          <doc xmlns:xi="http://www.w3.org/2001/XInclude">
    3999          <foo/>
    4000          <xi:include href="./test.xml" />
    4001          </doc>
    4002          ''')
    4003
    4004          class Resolver(etree.Resolver):
    4005              called = {}
    4006
    4007              def resolve(self, url, id, context):
    4008                  if url.endswith("test_xinclude.xml"):
    4009                      assert not self.called.get("input")
    4010                      self.called["input"] = True
    4011                      return None  # delegate to default resolver
    4012                  elif url.endswith('/test5.xml'):
    4013                      assert not self.called.get("DONE")
    4014                      self.called["DONE"] = True
    4015                      return self.resolve_string('<DONE/>', context)
    4016                  else:
    4017                      _, filename = url.rsplit('/', 1)
    4018                      assert not self.called.get(filename)
    4019                      self.called[filename] = True
    4020                      next_data = data.replace(
    4021                          'test.xml', 'test%d.xml' % len(self.called))
    4022                      return self.resolve_string(next_data, context)
    4023
    4024          res_instance = Resolver()
    4025          parser = etree.XMLParser(load_dtd=True)
    4026          parser.resolvers.add(res_instance)
    4027
    4028          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    4029                             parser=parser)
    4030
    4031          self.include(tree)
    4032
    4033          called = list(res_instance.called.items())
    4034          called.sort()
    4035          self.assertEqual(
    4036              [("DONE", True), ("input", True), ("test.xml", True),
    4037               ("test2.xml", True), ("test3.xml", True), ("test4.xml", True)],
    4038              called)
    4039
    4040
    4041 -class ETreeXIncludeTestCase(_XIncludeTestCase):
    4042 -    def include(self, tree):
    4043          tree.xinclude()
    4044
    4045
    4046 -class ElementIncludeTestCase(_XIncludeTestCase):
    4047      from lxml import ElementInclude
    4048 -    def include(self, tree):
    4049          self.ElementInclude.include(tree.getroot())
    4050
    4051
    4052 -class ETreeC14NTestCase(HelperTestCase):
    4053 -    def test_c14n(self):
    4054          tree = self.parse(_bytes('<a><b/></a>'))
    4055          f = BytesIO()
    4056          tree.write_c14n(f)
    4057          s = f.getvalue()
    4058          self.assertEqual(_bytes('<a><b></b></a>'),
    4059                            s)
    4060
    4061 -    def test_c14n_gzip(self):
    4062          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4063          f = BytesIO()
    4064          tree.write_c14n(f, compression=9)
    4065          gzfile = gzip.GzipFile(fileobj=BytesIO(f.getvalue()))
    4066          try:
    4067              s = gzfile.read()
    4068          finally:
    4069              gzfile.close()
    4070          self.assertEqual(_bytes('<a>'+'<b></b>'*200+'</a>'),
    4071                            s)
    4072
    4073 -    def test_c14n_file(self):
    4074          tree = self.parse(_bytes('<a><b/></a>'))
    4075          handle, filename = tempfile.mkstemp()
    4076          try:
    4077              tree.write_c14n(filename)
    4078              data = read_file(filename, 'rb')
    4079          finally:
    4080              os.close(handle)
    4081              os.remove(filename)
    4082          self.assertEqual(_bytes('<a><b></b></a>'),
    4083                            data)
    4084
    4085 -    def test_c14n_file_gzip(self):
    4086          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4087          handle, filename = tempfile.mkstemp()
    4088          try:
    4089              tree.write_c14n(filename, compression=9)
    4090              f = gzip.open(filename, 'rb')
    4091              try:
    4092                  data = f.read()
    4093              finally:
    4094                  f.close()
    4095          finally:
    4096              os.close(handle)
    4097              os.remove(filename)
    4098          self.assertEqual(_bytes('<a>'+'<b></b>'*200+'</a>'),
    4099                            data)
    4100
    4101 -    def test_c14n_with_comments(self):
    4102          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4103          f = BytesIO()
    4104          tree.write_c14n(f)
    4105          s = f.getvalue()
    4106          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4107                            s)
    4108          f = BytesIO()
    4109          tree.write_c14n(f, with_comments=True)
    4110          s = f.getvalue()
    4111          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4112                            s)
    4113          f = BytesIO()
    4114          tree.write_c14n(f, with_comments=False)
    4115          s = f.getvalue()
    4116          self.assertEqual(_bytes('<a><b></b></a>'),
    4117                            s)
    4118
    4119 -    def test_c14n_tostring_with_comments(self):
    4120          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4121          s = etree.tostring(tree, method='c14n')
    4122          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4123                            s)
    4124          s = etree.tostring(tree, method='c14n', with_comments=True)
    4125          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4126                            s)
    4127          s = etree.tostring(tree, method='c14n', with_comments=False)
    4128          self.assertEqual(_bytes('<a><b></b></a>'),
    4129                            s)
    4130
    4131 -    def test_c14n_element_tostring_with_comments(self):
    4132          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4133          s = etree.tostring(tree.getroot(), method='c14n')
    4134          self.assertEqual(_bytes('<a><!--ho--><b></b></a>'),
    4135                            s)
    4136          s = etree.tostring(tree.getroot(), method='c14n', with_comments=True)
    4137          self.assertEqual(_bytes('<a><!--ho--><b></b></a>'),
    4138                            s)
    4139          s = etree.tostring(tree.getroot(), method='c14n', with_comments=False)
    4140          self.assertEqual(_bytes('<a><b></b></a>'),
    4141                            s)
    4142
    4143 -    def test_c14n_exclusive(self):
    4144          tree = self.parse(_bytes(
    4145                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4146          f = BytesIO()
    4147          tree.write_c14n(f)
    4148          s = f.getvalue()
    4149          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4150                            s)
    4151          f = BytesIO()
    4152          tree.write_c14n(f, exclusive=False)
    4153          s = f.getvalue()
    4154          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4155                            s)
    4156          f = BytesIO()
    4157          tree.write_c14n(f, exclusive=True)
    4158          s = f.getvalue()
    4159          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4160                            s)
    4161
    4162          f = BytesIO()
    4163          tree.write_c14n(f, exclusive=True, inclusive_ns_prefixes=['z'])
    4164          s = f.getvalue()
    4165          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:z="http://cde"><z:b></z:b></a>'),
    4166                            s)
    4167
    4168 -    def test_c14n_tostring_exclusive(self):
    4169          tree = self.parse(_bytes(
    4170                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4171          s = etree.tostring(tree, method='c14n')
    4172          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4173                            s)
    4174          s = etree.tostring(tree, method='c14n', exclusive=False)
    4175          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4176                            s)
    4177          s = etree.tostring(tree, method='c14n', exclusive=True)
    4178          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4179                            s)
    4180
    4181          s = etree.tostring(tree, method='c14n', exclusive=True, inclusive_ns_prefixes=['y'])
    4182          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd"><z:b xmlns:z="http://cde"></z:b></a>'),
    4183                            s)
    4184
    4185 -    def test_c14n_element_tostring_exclusive(self):
    4186          tree = self.parse(_bytes(
    4187                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4188          s = etree.tostring(tree.getroot(), method='c14n')
    4189          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4190                            s)
    4191          s = etree.tostring(tree.getroot(), method='c14n', exclusive=False)
    4192          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4193                            s)
    4194          s = etree.tostring(tree.getroot(), method='c14n', exclusive=True)
    4195          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4196                            s)
    4197
    4198          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=False)
    4199          self.assertEqual(_bytes('<z:b xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'),
    4200                            s)
    4201          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True)
    4202          self.assertEqual(_bytes('<z:b xmlns:z="http://cde"></z:b>'),
    4203                            s)
    4204
    4205          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True, inclusive_ns_prefixes=['y'])
    4206          self.assertEqual(_bytes('<z:b xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'),
    4207                            s)
    4208
    4209 -    def test_c14n_tostring_inclusive_ns_prefixes(self):
    4210          """ Regression test to fix memory allocation issues (use 3+ inclusive NS spaces)"""
    4211          tree = self.parse(_bytes(
    4212                  '<a xmlns:x="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4213
    4214          s = etree.tostring(tree, method='c14n', exclusive=True, inclusive_ns_prefixes=['x', 'y', 'z'])
    4215          self.assertEqual(_bytes('<a xmlns:x="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4216                            s)
    4217
    4218
    4219 -class ETreeWriteTestCase(HelperTestCase):
    4220 -    def test_write(self):
    4221          tree = self.parse(_bytes('<a><b/></a>'))
    4222          f = BytesIO()
    4223          tree.write(f)
    4224          s = f.getvalue()
    4225          self.assertEqual(_bytes('<a><b/></a>'),
    4226                            s)
    4227
    4228 -    def test_write_gzip(self):
    4229          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4230          f = BytesIO()
    4231          tree.write(f, compression=9)
    4232          gzfile = gzip.GzipFile(fileobj=BytesIO(f.getvalue()))
    4233          try:
    4234              s = gzfile.read()
    4235          finally:
    4236              gzfile.close()
    4237          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4238                            s)
    4239
    4240 -    def test_write_gzip_level(self):
    4241          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4242          f = BytesIO()
    4243          tree.write(f, compression=0)
    4244          s0 = f.getvalue()
    4245
    4246          f = BytesIO()
    4247          tree.write(f)
    4248          self.assertEqual(f.getvalue(), s0)
    4249
    4250          f = BytesIO()
    4251          tree.write(f, compression=1)
    4252          s = f.getvalue()
    4253          self.assertTrue(len(s) <= len(s0))
    4254          gzfile = gzip.GzipFile(fileobj=BytesIO(s))
    4255          try:
    4256              s1 = gzfile.read()
    4257          finally:
    4258              gzfile.close()
    4259
    4260          f = BytesIO()
    4261          tree.write(f, compression=9)
    4262          s = f.getvalue()
    4263          self.assertTrue(len(s) <= len(s0))
    4264          gzfile = gzip.GzipFile(fileobj=BytesIO(s))
    4265          try:
    4266              s9 = gzfile.read()
    4267          finally:
    4268              gzfile.close()
    4269
    4270          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4271                            s0)
    4272          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4273                            s1)
    4274          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4275                            s9)
    4276
    4277 -    def test_write_file(self):
    4278          tree = self.parse(_bytes('<a><b/></a>'))
    4279          handle, filename = tempfile.mkstemp()
    4280          try:
    4281              tree.write(filename)
    4282              data = read_file(filename, 'rb')
    4283          finally:
    4284              os.close(handle)
    4285              os.remove(filename)
    4286          self.assertEqual(_bytes('<a><b/></a>'),
    4287                            data)
    4288
    4289 -    def test_write_file_gzip(self):
    4290          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4291          handle, filename = tempfile.mkstemp()
    4292          try:
    4293              tree.write(filename, compression=9)
    4294              f = gzip.open(filename, 'rb')
    4295              try:
    4296                  data = f.read()
    4297              finally:
    4298                  f.close()
    4299          finally:
    4300              os.close(handle)
    4301              os.remove(filename)
    4302          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4303                            data)
    4304
    4305 -    def test_write_file_gzip_parse(self):
    4306          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4307          handle, filename = tempfile.mkstemp()
    4308          try:
    4309              tree.write(filename, compression=9)
    4310              data = etree.tostring(etree.parse(filename))
    4311          finally:
    4312              os.close(handle)
    4313              os.remove(filename)
    4314          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4315                            data)
    4316
    4317 -    def test_write_file_gzipfile_parse(self):
    4318          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4319          handle, filename = tempfile.mkstemp()
    4320          try:
    4321              tree.write(filename, compression=9)
    4322              data = etree.tostring(etree.parse(
    4323                  gzip.GzipFile(filename)))
    4324          finally:
    4325              os.close(handle)
    4326              os.remove(filename)
    4327          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4328                            data)
    4329
    4330 -class ETreeErrorLogTest(HelperTestCase):
    4331      etree = etree
    4332
    4333 -    def test_parse_error_logging(self):
    4334          parse = self.etree.parse
    4335          f = BytesIO('<a><b></c></b></a>')
    4336          self.etree.clear_error_log()
    4337          try:
    4338              parse(f)
    4339              logs = None
    4340          except SyntaxError:
    4341              e = sys.exc_info()[1]
    4342              logs = e.error_log
    4343          f.close()
    4344          self.assertTrue([ log for log in logs
    4345                         if 'mismatch' in log.message ])
    4346          self.assertTrue([ log for log in logs
    4347                         if 'PARSER'   in log.domain_name])
    4348          self.assertTrue([ log for log in logs
    4349                         if 'ERR_TAG_NAME_MISMATCH' in log.type_name ])
    4350          self.assertTrue([ log for log in logs
    4351                         if 1 == log.line ])
    4352          self.assertTrue([ log for log in logs
    4353                         if 15 == log.column ])
    4354
    4355 -    def _test_python_error_logging(self):
    4356          """This can't really be tested as long as there isn't a way to
    4357          reset the logging setup ...
    4358          """
    4359          parse = self.etree.parse
    4360
    4361          messages = []
    4362          class Logger(self.etree.PyErrorLog):
    4363              def log(self, entry, message, *args):
    4364                  messages.append(message)
    4365
    4366          self.etree.use_global_python_log(Logger())
    4367          f = BytesIO('<a><b></c></b></a>')
    4368          try:
    4369              parse(f)
    4370          except SyntaxError:
    4371              pass
    4372          f.close()
    4373
    4374          self.assertTrue([ message for message in messages
    4375                         if 'mismatch' in message ])
    4376          self.assertTrue([ message for message in messages
    4377                         if ':PARSER:'   in message])
    4378          self.assertTrue([ message for message in messages
    4379                         if ':ERR_TAG_NAME_MISMATCH:' in message ])
    4380          self.assertTrue([ message for message in messages
    4381                         if ':1:15:' in message ])
    4382
    4383
    4384 -class XMLPullParserTest(unittest.TestCase):
    4385      etree = etree
    4386
    4387 -    def assert_event_tags(self, events, expected):
    4388          self.assertEqual([(action, elem.tag) for action, elem in events],
    4389                           expected)
    4390
    4391 -    def test_pull_from_simple_target(self):
    4392          class Target(object):
    4393              def start(self, tag, attrib):
    4394                  return 'start(%s)' % tag
    4395              def end(self, tag):
    4396                  return 'end(%s)' % tag
    4397              def close(self):
    4398                  return 'close()'
    4399
    4400          parser = self.etree.XMLPullParser(target=Target())
    4401          events = parser.read_events()
    4402
    4403          parser.feed('<root><element>')
    4404          self.assertFalse(list(events))
    4405          self.assertFalse(list(events))
    4406          parser.feed('</element><child>')
    4407          self.assertEqual([('end', 'end(element)')], list(events))
    4408          parser.feed('</child>')
    4409          self.assertEqual([('end', 'end(child)')], list(events))
    4410          parser.feed('</root>')
    4411          self.assertEqual([('end', 'end(root)')], list(events))
    4412          self.assertFalse(list(events))
    4413          self.assertEqual('close()', parser.close())
    4414
    4415 -    def test_pull_from_simple_target_start_end(self):
    4416          class Target(object):
    4417              def start(self, tag, attrib):
    4418                  return 'start(%s)' % tag
    4419              def end(self, tag):
    4420                  return 'end(%s)' % tag
    4421              def close(self):
    4422                  return 'close()'
    4423
    4424          parser = self.etree.XMLPullParser(
    4425              ['start', 'end'], target=Target())
    4426          events = parser.read_events()
    4427
    4428          parser.feed('<root><element>')
    4429          self.assertEqual(
    4430              [('start', 'start(root)'), ('start', 'start(element)')],
    4431              list(events))
    4432          self.assertFalse(list(events))
    4433          parser.feed('</element><child>')
    4434          self.assertEqual(
    4435              [('end', 'end(element)'), ('start', 'start(child)')],
    4436              list(events))
    4437          parser.feed('</child>')
    4438          self.assertEqual(
    4439              [('end', 'end(child)')],
    4440              list(events))
    4441          parser.feed('</root>')
    4442          self.assertEqual(
    4443              [('end', 'end(root)')],
    4444              list(events))
    4445          self.assertFalse(list(events))
    4446          self.assertEqual('close()', parser.close())
    4447
    4448 -    def test_pull_from_tree_builder(self):
    4449          parser = self.etree.XMLPullParser(
    4450              ['start', 'end'], target=etree.TreeBuilder())
    4451          events = parser.read_events()
    4452
    4453          parser.feed('<root><element>')
    4454          self.assert_event_tags(
    4455              events, [('start', 'root'), ('start', 'element')])
    4456          self.assertFalse(list(events))
    4457          parser.feed('</element><child>')
    4458          self.assert_event_tags(
    4459              events, [('end', 'element'), ('start', 'child')])
    4460          parser.feed('</child>')
    4461          self.assert_event_tags(
    4462              events, [('end', 'child')])
    4463          parser.feed('</root>')
    4464          self.assert_event_tags(
    4465              events, [('end', 'root')])
    4466          self.assertFalse(list(events))
    4467          root = parser.close()
    4468          self.assertEqual('root', root.tag)
    4469
    4470 -    def test_pull_from_tree_builder_subclass(self):
    4471          class Target(etree.TreeBuilder):
    4472              def end(self, tag):
    4473                  el = super(Target, self).end(tag)
    4474                  el.tag += '-huhu'
    4475                  return el
    4476
    4477          parser = self.etree.XMLPullParser(
    4478              ['start', 'end'], target=Target())
    4479          events = parser.read_events()
    4480
    4481          parser.feed('<root><element>')
    4482          self.assert_event_tags(
    4483              events, [('start', 'root'), ('start', 'element')])
    4484          self.assertFalse(list(events))
    4485          parser.feed('</element><child>')
    4486          self.assert_event_tags(
    4487              events, [('end', 'element-huhu'), ('start', 'child')])
    4488          parser.feed('</child>')
    4489          self.assert_event_tags(
    4490              events, [('end', 'child-huhu')])
    4491          parser.feed('</root>')
    4492          self.assert_event_tags(
    4493              events, [('end', 'root-huhu')])
    4494          self.assertFalse(list(events))
    4495          root = parser.close()
    4496          self.assertEqual('root-huhu', root.tag)
    4497
    4498
    4499 -def test_suite():
    4500      suite = unittest.TestSuite()
    4501      suite.addTests([unittest.makeSuite(ETreeOnlyTestCase)])
    4502      suite.addTests([unittest.makeSuite(ETreeXIncludeTestCase)])
    4503      suite.addTests([unittest.makeSuite(ElementIncludeTestCase)])
    4504      suite.addTests([unittest.makeSuite(ETreeC14NTestCase)])
    4505      suite.addTests([unittest.makeSuite(ETreeWriteTestCase)])
    4506      suite.addTests([unittest.makeSuite(ETreeErrorLogTest)])
    4507      suite.addTests([unittest.makeSuite(XMLPullParserTest)])
    4508
    4509      # add original doctests from ElementTree selftest modules
    4510      from . import selftest, selftest2
    4511      suite.addTests(doctest.DocTestSuite(selftest))
    4512      suite.addTests(doctest.DocTestSuite(selftest2))
    4513
    4514      # add doctests
    4515      suite.addTests(doctest.DocTestSuite(etree))
    4516      suite.addTests(
    4517          [make_doctest('../../../doc/tutorial.txt')])
    4518      if sys.version_info >= (2,6):
    4519          # now requires the 'with' statement
    4520          suite.addTests(
    4521              [make_doctest('../../../doc/api.txt')])
    4522      suite.addTests(
    4523          [make_doctest('../../../doc/FAQ.txt')])
    4524      suite.addTests(
    4525          [make_doctest('../../../doc/parsing.txt')])
    4526      suite.addTests(
    4527          [make_doctest('../../../doc/resolvers.txt')])
    4528      return suite
    4529
    4530  if __name__ == '__main__':
    4531      print('to test use test.py %s' % __file__)
    4532