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  Tests require Python 2.5 or later.
      7  """
      8
      9  from __future__ import with_statement
     10
     11  import unittest
     12  import tempfile, os, sys
     13
     14  this_dir = os.path.dirname(__file__)
     15  if this_dir not in sys.path:
     16      sys.path.insert(0, this_dir) # needed for Py3
     17
     18  from common_imports import etree, BytesIO, HelperTestCase, skipIf
     19
     20 -class _XmlFileTestCaseBase(HelperTestCase):
     21      _file = None  # to be set by specific subtypes below
     22
     23 -    def test_element(self):
     24          with etree.xmlfile(self._file) as xf:
     25              with xf.element('test'):
     26                  pass
     27          self.assertXml('<test></test>')
     28
     29 -    def test_element_write_text(self):
     30          with etree.xmlfile(self._file) as xf:
     31              with xf.element('test'):
     32                  xf.write('toast')
     33          self.assertXml('<test>toast</test>')
     34
     35 -    def test_element_nested(self):
     36          with etree.xmlfile(self._file) as xf:
     37              with xf.element('test'):
     38                  with xf.element('toast'):
     39                      with xf.element('taste'):
     40                          xf.write('conTent')
     41          self.assertXml('<test><toast><taste>conTent</taste></toast></test>')
     42
     43 -    def test_element_nested_with_text(self):
     44          with etree.xmlfile(self._file) as xf:
     45              with xf.element('test'):
     46                  xf.write('con')
     47                  with xf.element('toast'):
     48                      xf.write('tent')
     49                      with xf.element('taste'):
     50                          xf.write('inside')
     51                      xf.write('tnet')
     52                  xf.write('noc')
     53          self.assertXml('<test>con<toast>tent<taste>inside</taste>'
     54                         'tnet</toast>noc</test>')
     55
     56 -    def test_write_Element(self):
     57          with etree.xmlfile(self._file) as xf:
     58              xf.write(etree.Element('test'))
     59          self.assertXml('<test/>')
     60
     61 -    def test_write_Element_repeatedly(self):
     62          element = etree.Element('test')
     63          with etree.xmlfile(self._file) as xf:
     64              with xf.element('test'):
     65                  for i in range(100):
     66                      xf.write(element)
     67
     68          tree = self._parse_file()
     69          self.assertTrue(tree is not None)
     70          self.assertEqual(100, len(tree.getroot()))
     71          self.assertEqual(set(['test']), set(el.tag for el in tree.getroot()))
     72
     73 -    def test_namespace_nsmap(self):
     74          with etree.xmlfile(self._file) as xf:
     75              with xf.element('{nsURI}test', nsmap={'x': 'nsURI'}):
     76                  pass
     77          self.assertXml('<x:test xmlns:x="nsURI"></x:test>')
     78
     79 -    def test_namespace_nested_nsmap(self):
     80          with etree.xmlfile(self._file) as xf:
     81              with xf.element('test', nsmap={'x': 'nsURI'}):
     82                  with xf.element('{nsURI}toast'):
     83                      pass
     84          self.assertXml('<test xmlns:x="nsURI"><x:toast></x:toast></test>')
     85
     86 -    def test_anonymous_namespace(self):
     87          with etree.xmlfile(self._file) as xf:
     88              with xf.element('{nsURI}test'):
     89                  pass
     90          self.assertXml('<ns0:test xmlns:ns0="nsURI"></ns0:test>')
     91
     92 -    def test_namespace_nested_anonymous(self):
     93          with etree.xmlfile(self._file) as xf:
     94              with xf.element('test'):
     95                  with xf.element('{nsURI}toast'):
     96                      pass
     97          self.assertXml('<test><ns0:toast xmlns:ns0="nsURI"></ns0:toast></test>')
     98
     99 -    def test_default_namespace(self):
    100          with etree.xmlfile(self._file) as xf:
    101              with xf.element('{nsURI}test', nsmap={None: 'nsURI'}):
    102                  pass
    103          self.assertXml('<test xmlns="nsURI"></test>')
    104
    105 -    def test_nested_default_namespace(self):
    106          with etree.xmlfile(self._file) as xf:
    107              with xf.element('{nsURI}test', nsmap={None: 'nsURI'}):
    108                  with xf.element('{nsURI}toast'):
    109                      pass
    110          self.assertXml('<test xmlns="nsURI"><toast></toast></test>')
    111
    112 -    def test_nested_default_namespace_and_other(self):
    113          with etree.xmlfile(self._file) as xf:
    114              with xf.element('{nsURI}test', nsmap={None: 'nsURI', 'p': 'ns2'}):
    115                  with xf.element('{nsURI}toast'):
    116                      pass
    117                  with xf.element('{ns2}toast'):
    118                      pass
    119          self.assertXml(
    120              '<test xmlns="nsURI" xmlns:p="ns2"><toast></toast><p:toast></p:toast></test>')
    121
    122 -    def test_pi(self):
    123          with etree.xmlfile(self._file) as xf:
    124              xf.write(etree.ProcessingInstruction('pypi'))
    125              with xf.element('test'):
    126                  pass
    127          self.assertXml('<?pypi ?><test></test>')
    128
    129 -    def test_comment(self):
    130          with etree.xmlfile(self._file) as xf:
    131              xf.write(etree.Comment('a comment'))
    132              with xf.element('test'):
    133                  pass
    134          self.assertXml('<!--a comment--><test></test>')
    135
    136 -    def test_attribute(self):
    137          with etree.xmlfile(self._file) as xf:
    138              with xf.element('test', attrib={'k': 'v'}):
    139                  pass
    140          self.assertXml('<test k="v"></test>')
    141
    142 -    def test_attribute_extra(self):
    143          with etree.xmlfile(self._file) as xf:
    144              with xf.element('test', attrib={'k': 'v'}, n='N'):
    145                  pass
    146          self.assertXml('<test k="v" n="N"></test>')
    147
    148 -    def test_attribute_extra_duplicate(self):
    149          with etree.xmlfile(self._file) as xf:
    150              with xf.element('test', attrib={'k': 'v'}, k='V'):
    151                  pass
    152          self.assertXml('<test k="V"></test>')
    153
    154 -    def test_escaping(self):
    155          with etree.xmlfile(self._file) as xf:
    156              with xf.element('test'):
    157                  xf.write('Comments: <!-- text -->\n')
    158                  xf.write('Entities: &amp;')
    159          self.assertXml(
    160              '<test>Comments: &lt;!-- text --&gt;\nEntities: &amp;amp;</test>')
    161
    162 -    def test_encoding(self):
    163          with etree.xmlfile(self._file, encoding='utf16') as xf:
    164              with xf.element('test'):
    165                  xf.write('toast')
    166          self.assertXml('<test>toast</test>', encoding='utf16')
    167
    168 -    def test_buffering(self):
    169          with etree.xmlfile(self._file, buffered=False) as xf:
    170              with xf.element('test'):
    171                  self.assertXml("<test>")
    172                  xf.write('toast')
    173                  self.assertXml("<test>toast")
    174                  with xf.element('taste'):
    175                      self.assertXml("<test>toast<taste>")
    176                      xf.write('some', etree.Element("more"), "toast")
    177                      self.assertXml("<test>toast<taste>some<more/>toast")
    178                  self.assertXml("<test>toast<taste>some<more/>toast</taste>")
    179                  xf.write('end')
    180                  self.assertXml("<test>toast<taste>some<more/>toast</taste>end")
    181              self.assertXml("<test>toast<taste>some<more/>toast</taste>end</test>")
    182          self.assertXml("<test>toast<taste>some<more/>toast</taste>end</test>")
    183
    184 -    def test_flush(self):
    185          with etree.xmlfile(self._file, buffered=True) as xf:
    186              with xf.element('test'):
    187                  self.assertXml("")
    188                  xf.write('toast')
    189                  self.assertXml("")
    190                  with xf.element('taste'):
    191                      self.assertXml("")
    192                      xf.flush()
    193                      self.assertXml("<test>toast<taste>")
    194                  self.assertXml("<test>toast<taste>")
    195              self.assertXml("<test>toast<taste>")
    196          self.assertXml("<test>toast<taste></taste></test>")
    197
    198 -    def test_failure_preceding_text(self):
    199          try:
    200              with etree.xmlfile(self._file) as xf:
    201                  xf.write('toast')
    202          except etree.LxmlSyntaxError:
    203              self.assertTrue(True)
    204          else:
    205              self.assertTrue(False)
    206
    207 -    def test_failure_trailing_text(self):
    208          with etree.xmlfile(self._file) as xf:
    209              with xf.element('test'):
    210                  pass
    211              try:
    212                  xf.write('toast')
    213              except etree.LxmlSyntaxError:
    214                  self.assertTrue(True)
    215              else:
    216                  self.assertTrue(False)
    217
    218 -    def test_failure_trailing_Element(self):
    219          with etree.xmlfile(self._file) as xf:
    220              with xf.element('test'):
    221                  pass
    222              try:
    223                  xf.write(etree.Element('test'))
    224              except etree.LxmlSyntaxError:
    225                  self.assertTrue(True)
    226              else:
    227                  self.assertTrue(False)
    228
    229 -    def test_closing_out_of_order_in_error_case(self):
    230          cm_exit = None
    231          try:
    232              with etree.xmlfile(self._file) as xf:
    233                  x = xf.element('test')
    234                  cm_exit = x.__exit__
    235                  x.__enter__()
    236                  raise ValueError('123')
    237          except ValueError:
    238              self.assertTrue(cm_exit)
    239              try:
    240                  cm_exit(ValueError, ValueError("huhu"), None)
    241              except etree.LxmlSyntaxError:
    242                  self.assertTrue(True)
    243              else:
    244                  self.assertTrue(False)
    245          else:
    246              self.assertTrue(False)
    247
    248 -    def _read_file(self):
    249          pos = self._file.tell()
    250          self._file.seek(0)
    251          try:
    252              return self._file.read()
    253          finally:
    254              self._file.seek(pos)
    255
    256 -    def _parse_file(self):
    257          pos = self._file.tell()
    258          self._file.seek(0)
    259          try:
    260              return etree.parse(self._file)
    261          finally:
    262              self._file.seek(pos)
    263
    264 -    def tearDown(self):
    265          if self._file is not None:
    266              self._file.close()
    267
    268 -    def assertXml(self, expected, encoding='utf8'):
    269          self.assertEqual(self._read_file().decode(encoding), expected)
    270
    271
    272 -class BytesIOXmlFileTestCase(_XmlFileTestCaseBase):
    273 -    def setUp(self):
    274          self._file = BytesIO()
    275
    276 -    def test_filelike_close(self):
    277          with etree.xmlfile(self._file, close=True) as xf:
    278              with xf.element('test'):
    279                  pass
    280          self.assertRaises(ValueError, self._file.getvalue)
    281
    282
    283 -class TempXmlFileTestCase(_XmlFileTestCaseBase):
    284 -    def setUp(self):
    285          self._file = tempfile.TemporaryFile()
    286
    287
    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_write_declaration(self):
    422          with etree.htmlfile(self._file) as xf:
    423              try:
    424                  xf.write_declaration()
    425              except etree.LxmlSyntaxError:
    426                  self.assertTrue(True)
    427              else:
    428                  self.assertTrue(False)
    429              xf.write(etree.Element('html'))
    430
    431 -    def test_write_namespaced_element(self):
    432          with etree.htmlfile(self._file) as xf:
    433              xf.write(etree.Element('{some_ns}some_tag'))
    434          self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
    435
    436 -    def test_open_namespaced_element(self):
    437          with etree.htmlfile(self._file) as xf:
    438              with xf.element("{some_ns}some_tag"):
    439                  pass
    440          self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
    441
    442
    443 -def test_suite():
    444      suite = unittest.TestSuite()
    445      suite.addTests([unittest.makeSuite(BytesIOXmlFileTestCase),
    446                      unittest.makeSuite(TempXmlFileTestCase),
    447                      unittest.makeSuite(TempPathXmlFileTestCase),
    448                      unittest.makeSuite(SimpleFileLikeXmlFileTestCase),
    449                      unittest.makeSuite(HtmlFileTestCase),
    450                      ])
    451      return suite
    452
    453  if __name__ == '__main__':
    454      print('to test use test.py %s' % __file__)
    455