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