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