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, _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 -class TempPathXmlFileTestCase(_XmlFileTestCaseBase):
290 - def setUp(self):
291 self._tmpfile = tempfile.NamedTemporaryFile() 292 self._file = self._tmpfile.name
293
294 - def tearDown(self):
295 try: 296 self._tmpfile.close() 297 finally: 298 if os.path.exists(self._tmpfile.name): 299 os.unlink(self._tmpfile.name)
300
301 - def _read_file(self):
302 self._tmpfile.seek(0) 303 return self._tmpfile.read()
304
305 - def _parse_file(self):
306 self._tmpfile.seek(0) 307 return etree.parse(self._tmpfile)
308 309 @skipIf(True, "temp file behaviour is too platform specific here")
310 - def test_buffering(self):
311 pass
312 313 @skipIf(True, "temp file behaviour is too platform specific here")
314 - def test_flush(self):
315 pass
316
317 318 -class SimpleFileLikeXmlFileTestCase(_XmlFileTestCaseBase):
319 - class SimpleFileLike(object):
320 - def __init__(self, target):
321 self._target = target 322 self.write = target.write 323 self.tell = target.tell 324 self.seek = target.seek 325 self.closed = False
326
327 - def close(self):
328 assert not self.closed 329 self.closed = True 330 self._target.close()
331
332 - def setUp(self):
333 self._target = BytesIO() 334 self._file = self.SimpleFileLike(self._target)
335
336 - def _read_file(self):
337 return self._target.getvalue()
338
339 - def _parse_file(self):
340 pos = self._file.tell() 341 self._target.seek(0) 342 try: 343 return etree.parse(self._target) 344 finally: 345 self._target.seek(pos)
346
348 with etree.xmlfile(self._file) as xf: 349 with xf.element('test'): 350 pass 351 self.assertFalse(self._file.closed)
352
353 - def test_filelike_close(self):
354 with etree.xmlfile(self._file, close=True) as xf: 355 with xf.element('test'): 356 pass 357 self.assertTrue(self._file.closed) 358 self._file = None # prevent closing in tearDown()
359
360 361 -class HtmlFileTestCase(_XmlFileTestCaseBase):
362 - def setUp(self):
363 self._file = BytesIO()
364
365 - def test_void_elements(self):
366 # http://www.w3.org/TR/html5/syntax.html#elements-0 367 void_elements = set([ 368 "area", "base", "br", "col", "embed", "hr", "img", 369 "input", "keygen", "link", "meta", "param", 370 "source", "track", "wbr" 371 ]) 372 373 # FIXME: These don't get serialized as void elements. 374 void_elements.difference_update([ 375 'area', 'embed', 'keygen', 'source', 'track', 'wbr' 376 ]) 377 378 for tag in sorted(void_elements): 379 with etree.htmlfile(self._file) as xf: 380 xf.write(etree.Element(tag)) 381 self.assertXml('<%s>' % tag) 382 self._file = BytesIO()
383
385 elt = etree.Element("foo", attrib={'selected': 'bar'}) 386 387 with etree.htmlfile(self._file) as xf: 388 with xf.element("root"): 389 xf.write(elt) # 1 390 391 assert elt.text is None 392 xf.write(elt, method='xml') # 2 393 394 elt.text = "" 395 xf.write(elt, method='xml') # 3 396 397 self.assertXml( 398 '<root>' 399 '<foo selected></foo>' # 1 400 '<foo selected="bar"/>' # 2 401 '<foo selected="bar"></foo>' # 3 402 '</root>') 403 self._file = BytesIO()
404
406 # The htmlfile already outputs in xml mode for .element calls. This 407 # test actually illustrates a bug 408 409 with etree.htmlfile(self._file) as xf: 410 with xf.element("root"): 411 with xf.element('foo', attrib={'selected': 'bar'}): 412 pass 413 414 self.assertXml( 415 '<root>' 416 # '<foo selected></foo>' # FIXME: this is the correct output 417 # in html mode 418 '<foo selected="bar"></foo>' 419 '</root>') 420 self._file = BytesIO()
421
422 - def test_attribute_quoting(self):
423 with etree.htmlfile(self._file) as xf: 424 with xf.element("tagname", attrib={"attr": '"misquoted"'}): 425 xf.write("foo") 426 427 self.assertXml('<tagname attr="&quot;misquoted&quot;">foo</tagname>')
428
430 with etree.htmlfile(self._file) as xf: 431 with xf.element("tagname", attrib={"attr": _str('"misquöted\\u3344\\U00013344"')}): 432 xf.write("foo") 433 434 self.assertXml('<tagname attr="&quot;misqu&#246;ted&#13124;&#78660;&quot;">foo</tagname>')
435
436 - def test_unescaped_script(self):
437 with etree.htmlfile(self._file) as xf: 438 elt = etree.Element('script') 439 elt.text = "if (a < b);" 440 xf.write(elt) 441 self.assertXml('<script>if (a < b);</script>')
442
444 with etree.htmlfile(self._file) as xf: 445 with xf.element('script'): 446 xf.write("if (a < b);") 447 448 self.assertXml('<script>if (a < b);</script>')
449
450 - def test_write_declaration(self):
451 with etree.htmlfile(self._file) as xf: 452 try: 453 xf.write_declaration() 454 except etree.LxmlSyntaxError: 455 self.assertTrue(True) 456 else: 457 self.assertTrue(False) 458 xf.write(etree.Element('html'))
459
461 with etree.htmlfile(self._file) as xf: 462 xf.write(etree.Element('{some_ns}some_tag')) 463 self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
464
466 with etree.htmlfile(self._file) as xf: 467 with xf.element("{some_ns}some_tag"): 468 pass 469 self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
470
471 472 -def test_suite():
473 suite = unittest.TestSuite() 474 suite.addTests([unittest.makeSuite(BytesIOXmlFileTestCase), 475 unittest.makeSuite(TempXmlFileTestCase), 476 unittest.makeSuite(TempPathXmlFileTestCase), 477 unittest.makeSuite(SimpleFileLikeXmlFileTestCase), 478 unittest.makeSuite(HtmlFileTestCase), 479 ]) 480 return suite
481 482 if __name__ == '__main__': 483 print('to test use test.py %s' % __file__) 484