utils.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import sys
  4. import six
  5. import time
  6. import uuid
  7. import json
  8. import socket
  9. import inspect
  10. import hashlib
  11. import platform
  12. import threading
  13. import traceback
  14. import collections
  15. from functools import partial
  16. def getargspec(func):
  17. """
  18. Used because getargspec for python 2.7 does not accept functools.partial
  19. which is the type for pytest fixtures.
  20. getargspec excerpted from:
  21. sphinx.util.inspect
  22. ~~~~~~~~~~~~~~~~~~~
  23. Helpers for inspecting Python modules.
  24. :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
  25. :license: BSD, see LICENSE for details.
  26. Like inspect.getargspec but supports functools.partial as well.
  27. """
  28. # noqa: E731 type: (Any) -> Any
  29. if inspect.ismethod(func):
  30. func = func.__func__
  31. parts = 0, () # noqa: E731 type: Tuple[int, Tuple[unicode, ...]]
  32. if type(func) is partial:
  33. keywords = func.keywords
  34. if keywords is None:
  35. keywords = {}
  36. parts = len(func.args), keywords.keys()
  37. func = func.func
  38. if not inspect.isfunction(func):
  39. raise TypeError('%r is not a Python function' % func)
  40. args, varargs, varkw = inspect.getargs(func.__code__)
  41. func_defaults = func.__defaults__
  42. if func_defaults is None:
  43. func_defaults = []
  44. else:
  45. func_defaults = list(func_defaults)
  46. if parts[0]:
  47. args = args[parts[0]:]
  48. if parts[1]:
  49. for arg in parts[1]:
  50. i = args.index(arg) - len(args) # type: ignore
  51. del args[i]
  52. try:
  53. del func_defaults[i]
  54. except IndexError:
  55. pass
  56. return inspect.ArgSpec(args, varargs, varkw, func_defaults) # type: ignore
  57. if six.PY3:
  58. from traceback import format_exception_only
  59. else:
  60. from _compat import format_exception_only
  61. def md5(*args):
  62. m = hashlib.md5()
  63. for arg in args:
  64. part = arg.encode('utf-8')
  65. m.update(part)
  66. return m.hexdigest()
  67. def uuid4():
  68. return str(uuid.uuid4())
  69. def now():
  70. return int(round(1000 * time.time()))
  71. def platform_label():
  72. major_version, _, __ = platform.python_version_tuple()
  73. implementation = platform.python_implementation()
  74. return '{implementation}{major_version}'.format(implementation=implementation.lower(),
  75. major_version=major_version)
  76. def thread_tag():
  77. return '{0}-{1}'.format(os.getpid(), threading.current_thread().name)
  78. def host_tag():
  79. return socket.gethostname()
  80. def escape_non_unicode_symbols(item):
  81. if not (six.PY2 and isinstance(item, str)):
  82. return item
  83. def escape_symbol(s):
  84. try:
  85. s.decode(encoding='UTF-8')
  86. return s
  87. except UnicodeDecodeError:
  88. return repr(s)[1:-1]
  89. return ''.join(map(escape_symbol, item))
  90. def represent(item):
  91. """
  92. >>> represent(None)
  93. 'None'
  94. >>> represent(123)
  95. '123'
  96. >>> import six
  97. >>> expected = u"'hi'" if six.PY2 else "'hi'"
  98. >>> represent('hi') == expected
  99. True
  100. >>> expected = u"'привет'" if six.PY2 else "'привет'"
  101. >>> represent(u'привет') == expected
  102. True
  103. >>> represent(bytearray([0xd0, 0xbf])) # doctest: +ELLIPSIS
  104. "<... 'bytearray'>"
  105. >>> from struct import pack
  106. >>> result = "<type 'str'>" if six.PY2 else "<class 'bytes'>"
  107. >>> represent(pack('h', 0x89)) == result
  108. True
  109. >>> result = "<type 'int'>" if six.PY2 else "<class 'int'>"
  110. >>> represent(int) == result
  111. True
  112. >>> represent(represent) # doctest: +ELLIPSIS
  113. '<function represent at ...>'
  114. >>> represent([represent]) # doctest: +ELLIPSIS
  115. '[<function represent at ...>]'
  116. >>> class ClassWithName(object):
  117. ... pass
  118. >>> represent(ClassWithName)
  119. "<class 'utils.ClassWithName'>"
  120. """
  121. if six.PY2 and isinstance(item, str):
  122. try:
  123. item = item.decode(encoding='UTF-8')
  124. except UnicodeDecodeError:
  125. pass
  126. if isinstance(item, six.text_type):
  127. return u'\'%s\'' % item
  128. elif isinstance(item, (bytes, bytearray)):
  129. return repr(type(item))
  130. else:
  131. return repr(item)
  132. def func_parameters(func, *args, **kwargs):
  133. """
  134. >>> def helper(func):
  135. ... def wrapper(*args, **kwargs):
  136. ... params = func_parameters(func, *args, **kwargs)
  137. ... print(list(params.items()))
  138. ... return func(*args, **kwargs)
  139. ... return wrapper
  140. >>> @helper
  141. ... def args(a, b):
  142. ... pass
  143. >>> args(1, 2)
  144. [('a', '1'), ('b', '2')]
  145. >>> args(*(1,2))
  146. [('a', '1'), ('b', '2')]
  147. >>> args(1, b=2)
  148. [('a', '1'), ('b', '2')]
  149. >>> @helper
  150. ... def kwargs(a=1, b=2):
  151. ... pass
  152. >>> kwargs()
  153. [('a', '1'), ('b', '2')]
  154. >>> kwargs(a=3, b=4)
  155. [('a', '3'), ('b', '4')]
  156. >>> kwargs(b=4, a=3)
  157. [('a', '3'), ('b', '4')]
  158. >>> kwargs(a=3)
  159. [('a', '3'), ('b', '2')]
  160. >>> kwargs(b=4)
  161. [('a', '1'), ('b', '4')]
  162. >>> @helper
  163. ... def args_kwargs(a, b, c=3, d=4):
  164. ... pass
  165. >>> args_kwargs(1, 2)
  166. [('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]
  167. >>> args_kwargs(1, 2, d=5)
  168. [('a', '1'), ('b', '2'), ('c', '3'), ('d', '5')]
  169. >>> args_kwargs(1, 2, 5, 6)
  170. [('a', '1'), ('b', '2'), ('c', '5'), ('d', '6')]
  171. >>> args_kwargs(1, b=2)
  172. [('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]
  173. >>> @helper
  174. ... def varargs(*a):
  175. ... pass
  176. >>> varargs()
  177. []
  178. >>> varargs(1, 2)
  179. [('a', '(1, 2)')]
  180. >>> @helper
  181. ... def keywords(**a):
  182. ... pass
  183. >>> keywords()
  184. []
  185. >>> keywords(a=1, b=2)
  186. [('a', '1'), ('b', '2')]
  187. >>> @helper
  188. ... def args_varargs(a, b, *c):
  189. ... pass
  190. >>> args_varargs(1, 2)
  191. [('a', '1'), ('b', '2')]
  192. >>> args_varargs(1, 2, 2)
  193. [('a', '1'), ('b', '2'), ('c', '(2,)')]
  194. >>> @helper
  195. ... def args_kwargs_varargs(a, b, c=3, **d):
  196. ... pass
  197. >>> args_kwargs_varargs(1, 2)
  198. [('a', '1'), ('b', '2'), ('c', '3')]
  199. >>> args_kwargs_varargs(1, 2, 4, d=5, e=6)
  200. [('a', '1'), ('b', '2'), ('c', '4'), ('d', '5'), ('e', '6')]
  201. >>> @helper
  202. ... def args_kwargs_varargs_keywords(a, b=2, *c, **d):
  203. ... pass
  204. >>> args_kwargs_varargs_keywords(1)
  205. [('a', '1'), ('b', '2')]
  206. >>> args_kwargs_varargs_keywords(1, 2, 4, d=5, e=6)
  207. [('a', '1'), ('b', '2'), ('c', '(4,)'), ('d', '5'), ('e', '6')]
  208. >>> class Class(object):
  209. ... @staticmethod
  210. ... @helper
  211. ... def static_args(a, b):
  212. ... pass
  213. ...
  214. ... @classmethod
  215. ... @helper
  216. ... def method_args(cls, a, b):
  217. ... pass
  218. ...
  219. ... @helper
  220. ... def args(self, a, b):
  221. ... pass
  222. >>> cls = Class()
  223. >>> cls.args(1, 2)
  224. [('a', '1'), ('b', '2')]
  225. >>> cls.method_args(1, 2)
  226. [('a', '1'), ('b', '2')]
  227. >>> cls.static_args(1, 2)
  228. [('a', '1'), ('b', '2')]
  229. """
  230. parameters = {}
  231. arg_spec = getargspec(func) if six.PY2 else inspect.getfullargspec(func)
  232. arg_order = list(arg_spec.args)
  233. args_dict = dict(zip(arg_spec.args, args))
  234. if arg_spec.defaults:
  235. kwargs_defaults_dict = dict(zip(arg_spec.args[-len(arg_spec.defaults):], arg_spec.defaults))
  236. parameters.update(kwargs_defaults_dict)
  237. if arg_spec.varargs:
  238. arg_order.append(arg_spec.varargs)
  239. varargs = args[len(arg_spec.args):]
  240. parameters.update({arg_spec.varargs: varargs} if varargs else {})
  241. if arg_spec.args and arg_spec.args[0] in ['cls', 'self']:
  242. args_dict.pop(arg_spec.args[0], None)
  243. if kwargs:
  244. if sys.version_info < (3, 6):
  245. # Sort alphabetically as old python versions does
  246. # not preserve call order for kwargs
  247. arg_order.extend(sorted(list(kwargs.keys())))
  248. else:
  249. # Keep py3.6 behaviour to preserve kwargs order
  250. arg_order.extend(list(kwargs.keys()))
  251. parameters.update(kwargs)
  252. parameters.update(args_dict)
  253. items = parameters.iteritems() if six.PY2 else parameters.items()
  254. sorted_items = sorted(map(lambda kv: (kv[0], represent(kv[1])), items), key=lambda x: arg_order.index(x[0]))
  255. return collections.OrderedDict(sorted_items)
  256. def format_traceback(exc_traceback):
  257. return ''.join(traceback.format_tb(exc_traceback)) if exc_traceback else None
  258. def format_exception(etype, value):
  259. """
  260. >>> import sys
  261. >>> try:
  262. ... assert False, u'Привет'
  263. ... except AssertionError:
  264. ... etype, e, _ = sys.exc_info()
  265. ... format_exception(etype, e) # doctest: +ELLIPSIS
  266. 'AssertionError: ...\\n'
  267. >>> try:
  268. ... assert False, 'Привет'
  269. ... except AssertionError:
  270. ... etype, e, _ = sys.exc_info()
  271. ... format_exception(etype, e) # doctest: +ELLIPSIS
  272. 'AssertionError: ...\\n'
  273. >>> try:
  274. ... compile("bla u'Привет'", "fake.py", "exec")
  275. ... except SyntaxError:
  276. ... etype, e, _ = sys.exc_info()
  277. ... format_exception(etype, e) # doctest: +ELLIPSIS
  278. ' File "fake.py", line 1...SyntaxError: invalid syntax\\n'
  279. >>> try:
  280. ... compile("bla 'Привет'", "fake.py", "exec")
  281. ... except SyntaxError:
  282. ... etype, e, _ = sys.exc_info()
  283. ... format_exception(etype, e) # doctest: +ELLIPSIS
  284. ' File "fake.py", line 1...SyntaxError: invalid syntax\\n'
  285. >>> from hamcrest import assert_that, equal_to
  286. >>> try:
  287. ... assert_that('left', equal_to('right'))
  288. ... except AssertionError:
  289. ... etype, e, _ = sys.exc_info()
  290. ... format_exception(etype, e) # doctest: +ELLIPSIS
  291. "AssertionError: \\nExpected:...but:..."
  292. >>> try:
  293. ... assert_that(u'left', equal_to(u'right'))
  294. ... except AssertionError:
  295. ... etype, e, _ = sys.exc_info()
  296. ... format_exception(etype, e) # doctest: +ELLIPSIS
  297. "AssertionError: \\nExpected:...but:..."
  298. """
  299. return '\n'.join(format_exception_only(etype, value)) if etype or value else None
  300. def get_testplan():
  301. planned_tests = []
  302. file_path = os.environ.get("ALLURE_TESTPLAN_PATH")
  303. if file_path and os.path.exists(file_path):
  304. with open(file_path, 'r') as plan_file:
  305. plan = json.load(plan_file)
  306. planned_tests = plan.get("tests", [])
  307. return planned_tests