selftest2.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. # $Id: selftest.py 2213 2005-01-11 18:49:47Z fredrik $
  2. # elementtree selftest program
  3. # this test script uses Python's "doctest" module to check that the
  4. # *test script* works as expected.
  5. import sys
  6. try:
  7. from StringIO import StringIO
  8. BytesIO = StringIO
  9. except ImportError:
  10. from io import BytesIO, StringIO
  11. from lxml import etree as ElementTree
  12. def stdout():
  13. if sys.version_info[0] < 3:
  14. return sys.stdout
  15. class bytes_stdout(object):
  16. def write(self, data):
  17. if isinstance(data, bytes):
  18. data = data.decode('ISO8859-1')
  19. sys.stdout.write(data)
  20. return bytes_stdout()
  21. def unserialize(text):
  22. file = StringIO(text)
  23. tree = ElementTree.parse(file)
  24. return tree.getroot()
  25. def serialize(elem, encoding=None):
  26. file = BytesIO()
  27. tree = ElementTree.ElementTree(elem)
  28. if encoding:
  29. tree.write(file, encoding=encoding)
  30. else:
  31. tree.write(file)
  32. result = file.getvalue()
  33. if sys.version_info[0] >= 3:
  34. result = result.decode('ISO8859-1')
  35. result = result.replace(' />', '/>')
  36. if result[-1:] == '\n':
  37. result = result[:-1]
  38. return result
  39. def summarize(elem):
  40. return elem.tag
  41. def summarize_list(seq):
  42. return list(map(summarize, seq))
  43. SAMPLE_XML = unserialize("""
  44. <body>
  45. <tag>text</tag>
  46. <tag />
  47. <section>
  48. <tag>subtext</tag>
  49. </section>
  50. </body>
  51. """)
  52. SAMPLE_XML_NS = unserialize("""
  53. <body xmlns="http://effbot.org/ns">
  54. <tag>text</tag>
  55. <tag />
  56. <section>
  57. <tag>subtext</tag>
  58. </section>
  59. </body>
  60. """)
  61. # interface tests
  62. def check_string(string):
  63. len(string)
  64. for char in string:
  65. if len(char) != 1:
  66. print("expected one-character string, got %r" % char)
  67. new_string = string + ""
  68. new_string = string + " "
  69. string[:0]
  70. def check_mapping(mapping):
  71. len(mapping)
  72. keys = mapping.keys()
  73. items = mapping.items()
  74. for key in keys:
  75. item = mapping[key]
  76. mapping["key"] = "value"
  77. if mapping["key"] != "value":
  78. print("expected value string, got %r" % mapping["key"])
  79. def check_element(element):
  80. if not hasattr(element, "tag"):
  81. print("no tag member")
  82. if not hasattr(element, "attrib"):
  83. print("no attrib member")
  84. if not hasattr(element, "text"):
  85. print("no text member")
  86. if not hasattr(element, "tail"):
  87. print("no tail member")
  88. check_string(element.tag)
  89. check_mapping(element.attrib)
  90. if element.text != None:
  91. check_string(element.text)
  92. if element.tail != None:
  93. check_string(element.tail)
  94. def check_element_tree(tree):
  95. check_element(tree.getroot())
  96. def element():
  97. """
  98. Test element tree interface.
  99. >>> element = ElementTree.Element("tag")
  100. >>> check_element(element)
  101. >>> tree = ElementTree.ElementTree(element)
  102. >>> check_element_tree(tree)
  103. """
  104. def parsefile():
  105. """
  106. Test parsing from file. Note that we're opening the files in
  107. here; by default, the 'parse' function opens the file in binary
  108. mode, and doctest doesn't filter out carriage returns.
  109. >>> file = open("samples/simple.xml", "rb")
  110. >>> tree = ElementTree.parse(file)
  111. >>> file.close()
  112. >>> tree.write(stdout())
  113. <root>
  114. <element key="value">text</element>
  115. <element>text</element>tail
  116. <empty-element/>
  117. </root>
  118. >>> file = open("samples/simple-ns.xml", "rb")
  119. >>> tree = ElementTree.parse(file)
  120. >>> file.close()
  121. >>> tree.write(stdout())
  122. <root xmlns="http://namespace/">
  123. <element key="value">text</element>
  124. <element>text</element>tail
  125. <empty-element/>
  126. </root>
  127. """
  128. def writefile():
  129. """
  130. >>> elem = ElementTree.Element("tag")
  131. >>> elem.text = "text"
  132. >>> serialize(elem)
  133. '<tag>text</tag>'
  134. >>> ElementTree.SubElement(elem, "subtag").text = "subtext"
  135. >>> serialize(elem)
  136. '<tag>text<subtag>subtext</subtag></tag>'
  137. """
  138. def encoding():
  139. r"""
  140. Test encoding issues.
  141. >>> elem = ElementTree.Element("tag")
  142. >>> elem.text = u'abc'
  143. >>> serialize(elem)
  144. '<tag>abc</tag>'
  145. >>> serialize(elem, "utf-8")
  146. '<tag>abc</tag>'
  147. >>> serialize(elem, "us-ascii")
  148. '<tag>abc</tag>'
  149. >>> serialize(elem, "iso-8859-1").lower()
  150. "<?xml version='1.0' encoding='iso-8859-1'?>\n<tag>abc</tag>"
  151. >>> elem.text = "<&\"\'>"
  152. >>> serialize(elem)
  153. '<tag>&lt;&amp;"\'&gt;</tag>'
  154. >>> serialize(elem, "utf-8")
  155. '<tag>&lt;&amp;"\'&gt;</tag>'
  156. >>> serialize(elem, "us-ascii") # cdata characters
  157. '<tag>&lt;&amp;"\'&gt;</tag>'
  158. >>> serialize(elem, "iso-8859-1").lower()
  159. '<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<tag>&lt;&amp;"\'&gt;</tag>'
  160. >>> elem.attrib["key"] = "<&\"\'>"
  161. >>> elem.text = None
  162. >>> serialize(elem)
  163. '<tag key="&lt;&amp;&quot;\'&gt;"/>'
  164. >>> serialize(elem, "utf-8")
  165. '<tag key="&lt;&amp;&quot;\'&gt;"/>'
  166. >>> serialize(elem, "us-ascii")
  167. '<tag key="&lt;&amp;&quot;\'&gt;"/>'
  168. >>> serialize(elem, "iso-8859-1").lower()
  169. '<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<tag key="&lt;&amp;&quot;\'&gt;"/>'
  170. >>> elem.text = u'\xe5\xf6\xf6<>'
  171. >>> elem.attrib.clear()
  172. >>> serialize(elem)
  173. '<tag>&#229;&#246;&#246;&lt;&gt;</tag>'
  174. >>> serialize(elem, "utf-8")
  175. '<tag>\xc3\xa5\xc3\xb6\xc3\xb6&lt;&gt;</tag>'
  176. >>> serialize(elem, "us-ascii")
  177. '<tag>&#229;&#246;&#246;&lt;&gt;</tag>'
  178. >>> serialize(elem, "iso-8859-1").lower()
  179. "<?xml version='1.0' encoding='iso-8859-1'?>\n<tag>\xe5\xf6\xf6&lt;&gt;</tag>"
  180. >>> elem.attrib["key"] = u'\xe5\xf6\xf6<>'
  181. >>> elem.text = None
  182. >>> serialize(elem)
  183. '<tag key="&#229;&#246;&#246;&lt;&gt;"/>'
  184. >>> serialize(elem, "utf-8")
  185. '<tag key="\xc3\xa5\xc3\xb6\xc3\xb6&lt;&gt;"/>'
  186. >>> serialize(elem, "us-ascii")
  187. '<tag key="&#229;&#246;&#246;&lt;&gt;"/>'
  188. >>> serialize(elem, "iso-8859-1").lower()
  189. '<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<tag key="\xe5\xf6\xf6&lt;&gt;"/>'
  190. """
  191. if sys.version_info[0] >= 3:
  192. encoding.__doc__ = encoding.__doc__.replace("u'", "'")
  193. def qname():
  194. """
  195. Test QName handling.
  196. 1) decorated tags
  197. >>> elem = ElementTree.Element("{uri}tag")
  198. >>> serialize(elem) # 1.1
  199. '<ns0:tag xmlns:ns0="uri"/>'
  200. ## 2) decorated attributes
  201. ## >>> elem.attrib["{uri}key"] = "value"
  202. ## >>> serialize(elem) # 2.1
  203. ## '<ns0:tag ns0:key="value" xmlns:ns0="uri"/>'
  204. """
  205. def cdata():
  206. """
  207. Test CDATA handling (etc).
  208. >>> serialize(unserialize("<tag>hello</tag>"))
  209. '<tag>hello</tag>'
  210. >>> serialize(unserialize("<tag>&#104;&#101;&#108;&#108;&#111;</tag>"))
  211. '<tag>hello</tag>'
  212. >>> serialize(unserialize("<tag><![CDATA[hello]]></tag>"))
  213. '<tag>hello</tag>'
  214. """
  215. def find():
  216. """
  217. Test find methods (including xpath syntax).
  218. >>> elem = SAMPLE_XML
  219. >>> elem.find("tag").tag
  220. 'tag'
  221. >>> ElementTree.ElementTree(elem).find("tag").tag
  222. 'tag'
  223. >>> elem.find("section/tag").tag
  224. 'tag'
  225. >>> ElementTree.ElementTree(elem).find("section/tag").tag
  226. 'tag'
  227. >>> elem.findtext("tag")
  228. 'text'
  229. >>> elem.findtext("tog", "default")
  230. 'default'
  231. >>> ElementTree.ElementTree(elem).findtext("tag")
  232. 'text'
  233. >>> elem.findtext("section/tag")
  234. 'subtext'
  235. >>> ElementTree.ElementTree(elem).findtext("section/tag")
  236. 'subtext'
  237. >>> summarize_list(elem.findall("tag"))
  238. ['tag', 'tag']
  239. >>> summarize_list(elem.findall("*"))
  240. ['tag', 'tag', 'section']
  241. >>> summarize_list(elem.findall(".//tag"))
  242. ['tag', 'tag', 'tag']
  243. >>> summarize_list(elem.findall("section/tag"))
  244. ['tag']
  245. >>> summarize_list(elem.findall("section//tag"))
  246. ['tag']
  247. >>> summarize_list(elem.findall("section/*"))
  248. ['tag']
  249. >>> summarize_list(elem.findall("section//*"))
  250. ['tag']
  251. >>> summarize_list(elem.findall("section/.//*"))
  252. ['tag']
  253. >>> summarize_list(elem.findall("*/*"))
  254. ['tag']
  255. >>> summarize_list(elem.findall("*//*"))
  256. ['tag']
  257. >>> summarize_list(elem.findall("*/tag"))
  258. ['tag']
  259. >>> summarize_list(elem.findall("*/./tag"))
  260. ['tag']
  261. >>> summarize_list(elem.findall("./tag"))
  262. ['tag', 'tag']
  263. >>> summarize_list(elem.findall(".//tag"))
  264. ['tag', 'tag', 'tag']
  265. >>> summarize_list(elem.findall("././tag"))
  266. ['tag', 'tag']
  267. >>> summarize_list(ElementTree.ElementTree(elem).findall("/tag"))
  268. ['tag', 'tag']
  269. >>> summarize_list(ElementTree.ElementTree(elem).findall("./tag"))
  270. ['tag', 'tag']
  271. >>> elem = SAMPLE_XML_NS
  272. >>> summarize_list(elem.findall("tag"))
  273. []
  274. >>> summarize_list(elem.findall("{http://effbot.org/ns}tag"))
  275. ['{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag']
  276. >>> summarize_list(elem.findall(".//{http://effbot.org/ns}tag"))
  277. ['{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag']
  278. """
  279. # XXX only deep copying is supported
  280. def copy():
  281. """
  282. Test copy handling (etc).
  283. >>> import copy
  284. >>> e1 = unserialize("<tag>hello<foo/></tag>")
  285. >>> # e2 = copy.copy(e1)
  286. >>> e3 = copy.deepcopy(e1)
  287. >>> e1.find("foo").tag = "bar"
  288. >>> serialize(e1).replace(' ', '')
  289. '<tag>hello<bar/></tag>'
  290. ## >>> serialize(e2).replace(' ', '')
  291. ## '<tag>hello<bar/></tag>'
  292. >>> serialize(e3).replace(' ', '')
  293. '<tag>hello<foo/></tag>'
  294. """
  295. def attrib():
  296. """
  297. Test attribute handling.
  298. >>> elem = ElementTree.Element("tag")
  299. >>> elem.get("key") # 1.1
  300. >>> elem.get("key", "default") # 1.2
  301. 'default'
  302. >>> elem.set("key", "value")
  303. >>> elem.get("key") # 1.3
  304. 'value'
  305. >>> elem = ElementTree.Element("tag", key="value")
  306. >>> elem.get("key") # 2.1
  307. 'value'
  308. >>> elem.attrib # 2.2
  309. {'key': 'value'}
  310. >>> elem = ElementTree.Element("tag", {"key": "value"})
  311. >>> elem.get("key") # 3.1
  312. 'value'
  313. >>> elem.attrib # 3.2
  314. {'key': 'value'}
  315. >>> elem = ElementTree.Element("tag", {"key": "other"}, key="value")
  316. >>> elem.get("key") # 4.1
  317. 'value'
  318. >>> elem.attrib # 4.2
  319. {'key': 'value'}
  320. """
  321. def makeelement():
  322. """
  323. Test makeelement handling.
  324. >>> elem = ElementTree.Element("tag")
  325. >>> subelem = elem.makeelement("subtag", {"key": "value"})
  326. >>> elem.append(subelem)
  327. >>> serialize(elem)
  328. '<tag><subtag key="value"/></tag>'
  329. >>> elem.clear()
  330. >>> serialize(elem)
  331. '<tag/>'
  332. >>> elem.append(subelem)
  333. >>> serialize(elem)
  334. '<tag><subtag key="value"/></tag>'
  335. """
  336. ## def observer():
  337. ## """
  338. ## Test observers.
  339. ## >>> def observer(action, elem):
  340. ## ... print("%s %s" % (action, elem.tag))
  341. ## >>> builder = ElementTree.TreeBuilder()
  342. ## >>> builder.addobserver(observer)
  343. ## >>> parser = ElementTree.XMLParser(builder)
  344. ## >>> file = open("samples/simple.xml", "rb")
  345. ## >>> parser.feed(file.read())
  346. ## start root
  347. ## start element
  348. ## end element
  349. ## start element
  350. ## end element
  351. ## start empty-element
  352. ## end empty-element
  353. ## end root
  354. ## >>> file.close()
  355. ## """
  356. ENTITY_XML = """\
  357. <!DOCTYPE points [
  358. <!ENTITY % user-entities SYSTEM 'user-entities.xml'>
  359. %user-entities;
  360. ]>
  361. <document>&entity;</document>
  362. """
  363. ## def entity():
  364. ## """
  365. ## Test entity handling.
  366. ## 1) bad entities
  367. ## >>> ElementTree.XML("<document>&entity;</document>")
  368. ## Traceback (most recent call last):
  369. ## SyntaxError: undefined entity: line 1, column 10
  370. ## 2) custom entity
  371. ## >>> parser = ElementTree.XMLParser()
  372. ## >>> parser.entity["entity"] = "text"
  373. ## >>> parser.feed(ENTITY_XML)
  374. ## >>> root = parser.close()
  375. ## >>> serialize(root)
  376. ## '<document>text</document>'
  377. ## """
  378. if __name__ == "__main__":
  379. import doctest, selftest2
  380. failed, tested = doctest.testmod(selftest2)
  381. print("%d tests ok." % (tested - failed))
  382. if failed > 0:
  383. print("%d tests failed. Exiting with non-zero return code." % failed)
  384. sys.exit(1)