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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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