lxml.tests.test_incremental_xmlfile

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

# Source Code for Module lxml.tests.test_incremental_xmlfile

      1  # -*- coding: utf-8 -*-
      2
      3  """
      4  Tests for the incremental XML serialisation API.
      5  """
      6
      7  from __future__ import with_statement, absolute_import
      8
      9  import unittest
     10  import tempfile, os, sys
     11
     12  this_dir = os.path.dirname(__file__)
     13  if this_dir not in sys.path:
     14      sys.path.insert(0, this_dir) # needed for Py3
     15
     16  from .common_imports import etree, BytesIO, HelperTestCase, skipIf, _str
     17
     18
     19 -class _XmlFileTestCaseBase(HelperTestCase):
     20      _file = None  # to be set by specific subtypes below
     21
     22 -    def test_element(self):
     23          with etree.xmlfile(self._file) as xf:
     24              with xf.element('test'):
     25                  pass
     26          self.assertXml('<test></test>')
     27
     28 -    def test_element_write_text(self):
     29          with etree.xmlfile(self._file) as xf:
     30              with xf.element('test'):
     31                  xf.write('toast')
     32          self.assertXml('<test>toast</test>')
     33
     34 -    def test_element_nested(self):
     35          with etree.xmlfile(self._file) as xf:
     36              with xf.element('test'):
     37                  with xf.element('toast'):
     38                      with xf.element('taste'):
     39                          xf.write('conTent')
     40          self.assertXml('<test><toast><taste>conTent</taste></toast></test>')
     41
     42 -    def test_element_nested_with_text(self):
     43          with etree.xmlfile(self._file) as xf:
     44              with xf.element('test'):
     45                  xf.write('con')
     46                  with xf.element('toast'):
     47                      xf.write('tent')
     48                      with xf.element('taste'):
     49                          xf.write('inside')
     50                      xf.write('tnet')
     51                  xf.write('noc')
     52          self.assertXml('<test>con<toast>tent<taste>inside</taste>'
     53                         'tnet</toast>noc</test>')
     54
     55 -    def test_write_Element(self):
     56          with etree.xmlfile(self._file) as xf:
     57              xf.write(etree.Element('test'))
     58          self.assertXml('<test/>')
     59
     60 -    def test_write_Element_repeatedly(self):
     61          element = etree.Element('test')
     62          with etree.xmlfile(self._file) as xf:
     63              with xf.element('test'):
     64                  for i in range(100):
     65                      xf.write(element)
     66
     67          tree = self._parse_file()
     68          self.assertTrue(tree is not None)
     69          self.assertEqual(100, len(tree.getroot()))
     70          self.assertEqual(set(['test']), set(el.tag for el in tree.getroot()))
     71
     72 -    def test_namespace_nsmap(self):
     73          with etree.xmlfile(self._file) as xf:
     74              with xf.element('{nsURI}test', nsmap={'x': 'nsURI'}):
     75                  pass
     76          self.assertXml('<x:test xmlns:x="nsURI"></x:test>')
     77
     78 -    def test_namespace_nested_nsmap(self):
     79          with etree.xmlfile(self._file) as xf:
     80              with xf.element('test', nsmap={'x': 'nsURI'}):
     81                  with xf.element('{nsURI}toast'):
     82                      pass
     83          self.assertXml('<test xmlns:x="nsURI"><x:toast></x:toast></test>')
     84
     85 -    def test_anonymous_namespace(self):
     86          with etree.xmlfile(self._file) as xf:
     87              with xf.element('{nsURI}test'):
     88                  pass
     89          self.assertXml('<ns0:test xmlns:ns0="nsURI"></ns0:test>')
     90
     91 -    def test_namespace_nested_anonymous(self):
     92          with etree.xmlfile(self._file) as xf:
     93              with xf.element('test'):
     94                  with xf.element('{nsURI}toast'):
     95                      pass
     96          self.assertXml('<test><ns0:toast xmlns:ns0="nsURI"></ns0:toast></test>')
     97
     98 -    def test_default_namespace(self):
     99          with etree.xmlfile(self._file) as xf:
    100              with xf.element('{nsURI}test', nsmap={None: 'nsURI'}):
    101                  pass
    102          self.assertXml('<test xmlns="nsURI"></test>')
    103
    104 -    def test_nested_default_namespace(self):
    105          with etree.xmlfile(self._file) as xf:
    106              with xf.element('{nsURI}test', nsmap={None: 'nsURI'}):
    107                  with xf.element('{nsURI}toast'):
    108                      pass
    109          self.assertXml('<test xmlns="nsURI"><toast></toast></test>')
    110
    111 -    def test_nested_default_namespace_and_other(self):
    112          with etree.xmlfile(self._file) as xf:
    113              with xf.element('{nsURI}test', nsmap={None: 'nsURI', 'p': 'ns2'}):
    114                  with xf.element('{nsURI}toast'):
    115                      pass
    116                  with xf.element('{ns2}toast'):
    117                      pass
    118          self.assertXml(
    119              '<test xmlns="nsURI" xmlns:p="ns2"><toast></toast><p:toast></p:toast></test>')
    120
    121 -    def test_pi(self):
    122          with etree.xmlfile(self._file) as xf:
    123              xf.write(etree.ProcessingInstruction('pypi'))
    124              with xf.element('test'):
    125                  pass
    126          self.assertXml('<?pypi ?><test></test>')
    127
    128 -    def test_comment(self):
    129          with etree.xmlfile(self._file) as xf:
    130              xf.write(etree.Comment('a comment'))
    131              with xf.element('test'):
    132                  pass
    133          self.assertXml('<!--a comment--><test></test>')
    134
    135 -    def test_attribute(self):
    136          with etree.xmlfile(self._file) as xf:
    137              with xf.element('test', attrib={'k': 'v'}):
    138                  pass
    139          self.assertXml('<test k="v"></test>')
    140
    141 -    def test_attribute_extra(self):
    142          with etree.xmlfile(self._file) as xf:
    143              with xf.element('test', attrib={'k': 'v'}, n='N'):
    144                  pass
    145          self.assertXml('<test k="v" n="N"></test>')
    146
    147 -    def test_attribute_extra_duplicate(self):
    148          with etree.xmlfile(self._file) as xf:
    149              with xf.element('test', attrib={'k': 'v'}, k='V'):
    150                  pass
    151          self.assertXml('<test k="V"></test>')
    152
    153 -    def test_escaping(self):
    154          with etree.xmlfile(self._file) as xf:
    155              with xf.element('test'):
    156                  xf.write('Comments: <!-- text -->\n')
    157                  xf.write('Entities: &amp;')
    158          self.assertXml(
    159              '<test>Comments: &lt;!-- text --&gt;\nEntities: &amp;amp;</test>')
    160
    161 -    def test_encoding(self):
    162          with etree.xmlfile(self._file, encoding='utf16') as xf:
    163              with xf.element('test'):
    164                  xf.write('toast')
    165          self.assertXml('<test>toast</test>', encoding='utf16')
    166
    167 -    def test_buffering(self):
    168          with etree.xmlfile(self._file, buffered=False) as xf:
    169              with xf.element('test'):
    170                  self.assertXml("<test>")
    171                  xf.write('toast')
    172                  self.assertXml("<test>toast")
    173                  with xf.element('taste'):
    174                      self.assertXml("<test>toast<taste>")
    175                      xf.write('some', etree.Element("more"), "toast")
    176                      self.assertXml("<test>toast<taste>some<more/>toast")
    177                  self.assertXml("<test>toast<taste>some<more/>toast</taste>")
    178                  xf.write('end')
    179                  self.assertXml("<test>toast<taste>some<more/>toast</taste>end")
    180              self.assertXml("<test>toast<taste>some<more/>toast</taste>end</test>")
    181          self.assertXml("<test>toast<taste>some<more/>toast</taste>end</test>")
    182
    183 -    def test_flush(self):
    184          with etree.xmlfile(self._file, buffered=True) as xf:
    185              with xf.element('test'):
    186                  self.assertXml("")
    187                  xf.write('toast')
    188                  self.assertXml("")
    189                  with xf.element('taste'):
    190                      self.assertXml("")
    191                      xf.flush()
    192                      self.assertXml("<test>toast<taste>")
    193                  self.assertXml("<test>toast<taste>")
    194              self.assertXml("<test>toast<taste>")
    195          self.assertXml("<test>toast<taste></taste></test>")
    196
    197 -    def test_failure_preceding_text(self):
    198          try:
    199              with etree.xmlfile(self._file) as xf:
    200                  xf.write('toast')
    201          except etree.LxmlSyntaxError:
    202              self.assertTrue(True)
    203          else:
    204              self.assertTrue(False)
    205
    206 -    def test_failure_trailing_text(self):
    207          with etree.xmlfile(self._file) as xf:
    208              with xf.element('test'):
    209                  pass
    210              try:
    211                  xf.write('toast')
    212              except etree.LxmlSyntaxError:
    213                  self.assertTrue(True)
    214              else:
    215                  self.assertTrue(False)
    216
    217 -    def test_failure_trailing_Element(self):
    218          with etree.xmlfile(self._file) as xf:
    219              with xf.element('test'):
    220                  pass
    221              try:
    222                  xf.write(etree.Element('test'))
    223              except etree.LxmlSyntaxError:
    224                  self.assertTrue(True)
    225              else:
    226                  self.assertTrue(False)
    227
    228 -    def test_closing_out_of_order_in_error_case(self):
    229          cm_exit = None
    230          try:
    231              with etree.xmlfile(self._file) as xf:
    232                  x = xf.element('test')
    233                  cm_exit = x.__exit__
    234                  x.__enter__()
    235                  raise ValueError('123')
    236          except ValueError:
    237              self.assertTrue(cm_exit)
    238              try:
    239                  cm_exit(ValueError, ValueError("huhu"), None)
    240              except etree.LxmlSyntaxError:
    241                  self.assertTrue(True)
    242              else:
    243                  self.assertTrue(False)
    244          else:
    245              self.assertTrue(False)
    246
    247 -    def _read_file(self):
    248          pos = self._file.tell()
    249          self._file.seek(0)
    250          try:
    251              return self._file.read()
    252          finally:
    253              self._file.seek(pos)
    254
    255 -    def _parse_file(self):
    256          pos = self._file.tell()
    257          self._file.seek(0)
    258          try:
    259              return etree.parse(self._file)
    260          finally:
    261              self._file.seek(pos)
    262
    263 -    def tearDown(self):
    264          if self._file is not None:
    265              self._file.close()
    266
    267 -    def assertXml(self, expected, encoding='utf8'):
    268          self.assertEqual(self._read_file().decode(encoding), expected)
    269
    270
    271 -class BytesIOXmlFileTestCase(_XmlFileTestCaseBase):
    272 -    def setUp(self):
    273          self._file = BytesIO()
    274
    275 -    def test_filelike_close(self):
    276          with etree.xmlfile(self._file, close=True) as xf:
    277              with xf.element('test'):
    278                  pass
    279          self.assertRaises(ValueError, self._file.getvalue)
    280
    281
    282 -class TempXmlFileTestCase(_XmlFileTestCaseBase):
    283 -    def setUp(self):
    284          self._file = tempfile.TemporaryFile()
    285
    286
    287  @skipIf(sys.platform.startswith("win"), "Can't reopen temporary files on Windows")
    288 -class TempPathXmlFileTestCase(_XmlFileTestCaseBase):
    289 -    def setUp(self):
    290          self._tmpfile = tempfile.NamedTemporaryFile()
    291          self._file = self._tmpfile.name
    292
    293 -    def tearDown(self):
    294          try:
    295              self._tmpfile.close()
    296          finally:
    297              if os.path.exists(self._tmpfile.name):
    298                  os.unlink(self._tmpfile.name)
    299
    300 -    def _read_file(self):
    301          self._tmpfile.seek(0)
    302          return self._tmpfile.read()
    303
    304 -    def _parse_file(self):
    305          self._tmpfile.seek(0)
    306          return etree.parse(self._tmpfile)
    307
    308      @skipIf(True, "temp file behaviour is too platform specific here")
    309 -    def test_buffering(self):
    310          pass
    311
    312      @skipIf(True, "temp file behaviour is too platform specific here")
    313 -    def test_flush(self):
    314          pass
    315
    316
    317 -class SimpleFileLikeXmlFileTestCase(_XmlFileTestCaseBase):
    318 -    class SimpleFileLike(object):
    319 -        def __init__(self, target):
    320              self._target = target
    321              self.write = target.write
    322              self.tell = target.tell
    323              self.seek = target.seek
    324              self.closed = False
    325
    326 -        def close(self):
    327              assert not self.closed
    328              self.closed = True
    329              self._target.close()
    330
    331 -    def setUp(self):
    332          self._target = BytesIO()
    333          self._file = self.SimpleFileLike(self._target)
    334
    335 -    def _read_file(self):
    336          return self._target.getvalue()
    337
    338 -    def _parse_file(self):
    339          pos = self._file.tell()
    340          self._target.seek(0)
    341          try:
    342              return etree.parse(self._target)
    343          finally:
    344              self._target.seek(pos)
    345
    346 -    def test_filelike_not_closing(self):
    347          with etree.xmlfile(self._file) as xf:
    348              with xf.element('test'):
    349                  pass
    350          self.assertFalse(self._file.closed)
    351
    352 -    def test_filelike_close(self):
    353          with etree.xmlfile(self._file, close=True) as xf:
    354              with xf.element('test'):
    355                  pass
    356          self.assertTrue(self._file.closed)
    357          self._file = None  # prevent closing in tearDown()
    358
    359
    360 -class HtmlFileTestCase(_XmlFileTestCaseBase):
    361 -    def setUp(self):
    362          self._file = BytesIO()
    363
    364 -    def test_void_elements(self):
    365          # http://www.w3.org/TR/html5/syntax.html#elements-0
    366          void_elements = set([
    367              "area", "base", "br", "col", "embed", "hr", "img",
    368              "input", "keygen", "link", "meta", "param",
    369              "source", "track", "wbr"
    370          ])
    371
    372          # FIXME: These don't get serialized as void elements.
    373          void_elements.difference_update([
    374              'area', 'embed', 'keygen', 'source', 'track', 'wbr'
    375          ])
    376
    377          for tag in sorted(void_elements):
    378              with etree.htmlfile(self._file) as xf:
    379                  xf.write(etree.Element(tag))
    380              self.assertXml('<%s>' % tag)
    381              self._file = BytesIO()
    382
    383 -    def test_xml_mode_write_inside_html(self):
    384          elt = etree.Element("foo", attrib={'selected': 'bar'})
    385
    386          with etree.htmlfile(self._file) as xf:
    387              with xf.element("root"):
    388                  xf.write(elt)  # 1
    389
    390                  assert elt.text is None
    391                  xf.write(elt, method='xml')  # 2
    392
    393                  elt.text = ""
    394                  xf.write(elt, method='xml')  # 3
    395
    396          self.assertXml(
    397              '<root>'
    398                  '<foo selected></foo>'  # 1
    399                  '<foo selected="bar"/>'  # 2
    400                  '<foo selected="bar"></foo>'  # 3
    401              '</root>')
    402          self._file = BytesIO()
    403
    404 -    def test_xml_mode_element_inside_html(self):
    405          # The htmlfile already outputs in xml mode for .element calls. This
    406          # test actually illustrates a bug
    407
    408          with etree.htmlfile(self._file) as xf:
    409              with xf.element("root"):
    410                  with xf.element('foo', attrib={'selected': 'bar'}):
    411                      pass
    412
    413          self.assertXml(
    414              '<root>'
    415                # '<foo selected></foo>'  # FIXME: this is the correct output
    416                                          # in html mode
    417                '<foo selected="bar"></foo>'
    418              '</root>')
    419          self._file = BytesIO()
    420
    421 -    def test_attribute_quoting(self):
    422          with etree.htmlfile(self._file) as xf:
    423              with xf.element("tagname", attrib={"attr": '"misquoted"'}):
    424                  xf.write("foo")
    425
    426          self.assertXml('<tagname attr="&quot;misquoted&quot;">foo</tagname>')
    427
    428 -    def test_attribute_quoting_unicode(self):
    429          with etree.htmlfile(self._file) as xf:
    430              with xf.element("tagname", attrib={"attr": _str('"misquöted\\u3344\\U00013344"')}):
    431                  xf.write("foo")
    432
    433          self.assertXml('<tagname attr="&quot;misqu&#246;ted&#13124;&#78660;&quot;">foo</tagname>')
    434
    435 -    def test_unescaped_script(self):
    436          with etree.htmlfile(self._file) as xf:
    437              elt = etree.Element('script')
    438              elt.text = "if (a < b);"
    439              xf.write(elt)
    440          self.assertXml('<script>if (a < b);</script>')
    441
    442 -    def test_unescaped_script_incremental(self):
    443          with etree.htmlfile(self._file) as xf:
    444              with xf.element('script'):
    445                  xf.write("if (a < b);")
    446
    447          self.assertXml('<script>if (a < b);</script>')
    448
    449 -    def test_write_declaration(self):
    450          with etree.htmlfile(self._file) as xf:
    451              try:
    452                  xf.write_declaration()
    453              except etree.LxmlSyntaxError:
    454                  self.assertTrue(True)
    455              else:
    456                  self.assertTrue(False)
    457              xf.write(etree.Element('html'))
    458
    459 -    def test_write_namespaced_element(self):
    460          with etree.htmlfile(self._file) as xf:
    461              xf.write(etree.Element('{some_ns}some_tag'))
    462          self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
    463
    464 -    def test_open_namespaced_element(self):
    465          with etree.htmlfile(self._file) as xf:
    466              with xf.element("{some_ns}some_tag"):
    467                  pass
    468          self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
    469
    470
    471 -def test_suite():
    472      suite = unittest.TestSuite()
    473      suite.addTests([unittest.makeSuite(BytesIOXmlFileTestCase),
    474                      unittest.makeSuite(TempXmlFileTestCase),
    475                      unittest.makeSuite(TempPathXmlFileTestCase),
    476                      unittest.makeSuite(SimpleFileLikeXmlFileTestCase),
    477                      unittest.makeSuite(HtmlFileTestCase),
    478                      ])
    479      return suite
    480
    481  if __name__ == '__main__':
    482      print('to test use test.py %s' % __file__)
    483