selftest2.py 11 KB

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