common_imports.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import os
  2. import os.path
  3. import re
  4. import gc
  5. import sys
  6. import unittest
  7. try:
  8. import urlparse
  9. except ImportError:
  10. import urllib.parse as urlparse
  11. try:
  12. from urllib import pathname2url
  13. except:
  14. from urllib.request import pathname2url
  15. def make_version_tuple(version_string):
  16. l = []
  17. for part in re.findall('([0-9]+|[^0-9.]+)', version_string):
  18. try:
  19. l.append(int(part))
  20. except ValueError:
  21. l.append(part)
  22. return tuple(l)
  23. IS_PYPY = (getattr(sys, 'implementation', None) == 'pypy' or
  24. getattr(sys, 'pypy_version_info', None) is not None)
  25. IS_PYTHON3 = sys.version_info[0] >= 3
  26. try:
  27. from xml.etree import ElementTree # Python 2.5+
  28. except ImportError:
  29. try:
  30. from elementtree import ElementTree # standard ET
  31. except ImportError:
  32. ElementTree = None
  33. if hasattr(ElementTree, 'VERSION'):
  34. ET_VERSION = make_version_tuple(ElementTree.VERSION)
  35. else:
  36. ET_VERSION = (0,0,0)
  37. try:
  38. from xml.etree import cElementTree # Python 2.5+
  39. except ImportError:
  40. try:
  41. import cElementTree # standard ET
  42. except ImportError:
  43. cElementTree = None
  44. if hasattr(cElementTree, 'VERSION'):
  45. CET_VERSION = make_version_tuple(cElementTree.VERSION)
  46. else:
  47. CET_VERSION = (0,0,0)
  48. def filter_by_version(test_class, version_dict, current_version):
  49. """Remove test methods that do not work with the current lib version.
  50. """
  51. find_required_version = version_dict.get
  52. def dummy_test_method(self):
  53. pass
  54. for name in dir(test_class):
  55. expected_version = find_required_version(name, (0,0,0))
  56. if expected_version > current_version:
  57. setattr(test_class, name, dummy_test_method)
  58. try:
  59. import doctest
  60. # check if the system version has everything we need
  61. doctest.DocFileSuite
  62. doctest.DocTestParser
  63. doctest.NORMALIZE_WHITESPACE
  64. doctest.ELLIPSIS
  65. except (ImportError, AttributeError):
  66. # we need our own version to make it work (Python 2.3?)
  67. import local_doctest as doctest
  68. try:
  69. sorted
  70. except NameError:
  71. def sorted(seq, **kwargs):
  72. seq = list(seq)
  73. seq.sort(**kwargs)
  74. return seq
  75. else:
  76. locals()['sorted'] = sorted
  77. try:
  78. next
  79. except NameError:
  80. def next(it):
  81. return it.next()
  82. else:
  83. locals()['next'] = next
  84. try:
  85. import pytest
  86. except ImportError:
  87. class skipif(object):
  88. "Using a class because a function would bind into a method when used in classes"
  89. def __init__(self, *args): pass
  90. def __call__(self, func, *args): return func
  91. else:
  92. skipif = pytest.mark.skipif
  93. def _get_caller_relative_path(filename, frame_depth=2):
  94. module = sys.modules[sys._getframe(frame_depth).f_globals['__name__']]
  95. return os.path.normpath(os.path.join(
  96. os.path.dirname(getattr(module, '__file__', '')), filename))
  97. from io import StringIO
  98. if sys.version_info[0] >= 3:
  99. # Python 3
  100. from builtins import str as unicode
  101. def _str(s, encoding="UTF-8"):
  102. return s
  103. def _bytes(s, encoding="UTF-8"):
  104. return s.encode(encoding)
  105. from io import BytesIO as _BytesIO
  106. def BytesIO(*args):
  107. if args and isinstance(args[0], str):
  108. args = (args[0].encode("UTF-8"),)
  109. return _BytesIO(*args)
  110. doctest_parser = doctest.DocTestParser()
  111. _fix_unicode = re.compile(r'(\s+)u(["\'])').sub
  112. _fix_exceptions = re.compile(r'(.*except [^(]*),\s*(.*:)').sub
  113. def make_doctest(filename):
  114. filename = _get_caller_relative_path(filename)
  115. doctests = read_file(filename)
  116. doctests = _fix_unicode(r'\1\2', doctests)
  117. doctests = _fix_exceptions(r'\1 as \2', doctests)
  118. return doctest.DocTestCase(
  119. doctest_parser.get_doctest(
  120. doctests, {}, os.path.basename(filename), filename, 0))
  121. else:
  122. # Python 2
  123. from __builtin__ import unicode
  124. def _str(s, encoding="UTF-8"):
  125. return unicode(s, encoding=encoding)
  126. def _bytes(s, encoding="UTF-8"):
  127. return s
  128. from io import BytesIO
  129. doctest_parser = doctest.DocTestParser()
  130. _fix_traceback = re.compile(r'^(\s*)(?:\w+\.)+(\w*(?:Error|Exception|Invalid):)', re.M).sub
  131. _fix_exceptions = re.compile(r'(.*except [^(]*)\s+as\s+(.*:)').sub
  132. _fix_bytes = re.compile(r'(\s+)b(["\'])').sub
  133. def make_doctest(filename):
  134. filename = _get_caller_relative_path(filename)
  135. doctests = read_file(filename)
  136. doctests = _fix_traceback(r'\1\2', doctests)
  137. doctests = _fix_exceptions(r'\1, \2', doctests)
  138. doctests = _fix_bytes(r'\1\2', doctests)
  139. return doctest.DocTestCase(
  140. doctest_parser.get_doctest(
  141. doctests, {}, os.path.basename(filename), filename, 0))
  142. try:
  143. skipIf = unittest.skipIf
  144. except AttributeError:
  145. def skipIf(condition, why,
  146. _skip=lambda test_method: None,
  147. _keep=lambda test_method: test_method):
  148. if condition:
  149. return _skip
  150. return _keep
  151. class HelperTestCase(unittest.TestCase):
  152. def tearDown(self):
  153. gc.collect()
  154. def parse(self, text, parser=None):
  155. f = BytesIO(text) if isinstance(text, bytes) else StringIO(text)
  156. return etree.parse(f, parser=parser)
  157. def _rootstring(self, tree):
  158. return etree.tostring(tree.getroot()).replace(
  159. _bytes(' '), _bytes('')).replace(_bytes('\n'), _bytes(''))
  160. # assertFalse doesn't exist in Python 2.3
  161. try:
  162. unittest.TestCase.assertFalse
  163. except AttributeError:
  164. assertFalse = unittest.TestCase.failIf
  165. class SillyFileLike:
  166. def __init__(self, xml_data=_bytes('<foo><bar/></foo>')):
  167. self.xml_data = xml_data
  168. def read(self, amount=None):
  169. if self.xml_data:
  170. if amount:
  171. data = self.xml_data[:amount]
  172. self.xml_data = self.xml_data[amount:]
  173. else:
  174. data = self.xml_data
  175. self.xml_data = _bytes('')
  176. return data
  177. return _bytes('')
  178. class LargeFileLike:
  179. def __init__(self, charlen=100, depth=4, children=5):
  180. self.data = BytesIO()
  181. self.chars = _bytes('a') * charlen
  182. self.children = range(children)
  183. self.more = self.iterelements(depth)
  184. def iterelements(self, depth):
  185. yield _bytes('<root>')
  186. depth -= 1
  187. if depth > 0:
  188. for child in self.children:
  189. for element in self.iterelements(depth):
  190. yield element
  191. yield self.chars
  192. else:
  193. yield self.chars
  194. yield _bytes('</root>')
  195. def read(self, amount=None):
  196. data = self.data
  197. append = data.write
  198. if amount:
  199. for element in self.more:
  200. append(element)
  201. if data.tell() >= amount:
  202. break
  203. else:
  204. for element in self.more:
  205. append(element)
  206. result = data.getvalue()
  207. data.seek(0)
  208. data.truncate()
  209. if amount:
  210. append(result[amount:])
  211. result = result[:amount]
  212. return result
  213. class LargeFileLikeUnicode(LargeFileLike):
  214. def __init__(self, charlen=100, depth=4, children=5):
  215. LargeFileLike.__init__(self, charlen, depth, children)
  216. self.data = StringIO()
  217. self.chars = _str('a') * charlen
  218. self.more = self.iterelements(depth)
  219. def iterelements(self, depth):
  220. yield _str('<root>')
  221. depth -= 1
  222. if depth > 0:
  223. for child in self.children:
  224. for element in self.iterelements(depth):
  225. yield element
  226. yield self.chars
  227. else:
  228. yield self.chars
  229. yield _str('</root>')
  230. def fileInTestDir(name):
  231. _testdir = os.path.dirname(__file__)
  232. return os.path.join(_testdir, name)
  233. def path2url(path):
  234. return urlparse.urljoin(
  235. 'file:', pathname2url(path))
  236. def fileUrlInTestDir(name):
  237. return path2url(fileInTestDir(name))
  238. def read_file(name, mode='r'):
  239. f = open(name, mode)
  240. try:
  241. data = f.read()
  242. finally:
  243. f.close()
  244. return data
  245. def write_to_file(name, data, mode='w'):
  246. f = open(name, mode)
  247. try:
  248. data = f.write(data)
  249. finally:
  250. f.close()
  251. def readFileInTestDir(name, mode='r'):
  252. return read_file(fileInTestDir(name), mode)
  253. def canonicalize(xml):
  254. tree = etree.parse(BytesIO(xml) if isinstance(xml, bytes) else StringIO(xml))
  255. f = BytesIO()
  256. tree.write_c14n(f)
  257. return f.getvalue()
  258. def unentitify(xml):
  259. for entity_name, value in re.findall("(&#([0-9]+);)", xml):
  260. xml = xml.replace(entity_name, unichr(int(value)))
  261. return xml