import os
import string
import sys
import time
import uuid
import json
import socket
import inspect
import hashlib
import platform
import threading
import traceback
import collections
from traceback import format_exception_only
def md5(*args):
m = hashlib.md5()
for arg in args:
part = arg.encode('utf-8')
m.update(part)
return m.hexdigest()
def uuid4():
return str(uuid.uuid4())
def now():
return int(round(1000 * time.time()))
def platform_label():
major_version, *_ = platform.python_version_tuple()
implementation = platform.python_implementation().lower()
return f'{implementation}{major_version}'
def thread_tag():
return '{0}-{1}'.format(os.getpid(), threading.current_thread().name)
def host_tag():
return socket.gethostname()
def represent(item):
"""
>>> represent(None)
'None'
>>> represent(123)
'123'
>>> represent('hi')
"'hi'"
>>> represent('')
"''"
>>> represent(bytearray([0xd0, 0xbf])) # doctest: +ELLIPSIS
""
>>> from struct import pack
>>> represent(pack('h', 0x89))
""
>>> represent(int)
""
>>> represent(represent) # doctest: +ELLIPSIS
''
>>> represent([represent]) # doctest: +ELLIPSIS
'[]'
>>> class ClassWithName:
... pass
>>> represent(ClassWithName)
""
"""
if isinstance(item, str):
return f"'{item}'"
elif isinstance(item, (bytes, bytearray)):
return repr(type(item))
else:
return repr(item)
def func_parameters(func, *args, **kwargs):
"""
>>> def helper(func):
... def wrapper(*args, **kwargs):
... params = func_parameters(func, *args, **kwargs)
... print(list(params.items()))
... return func(*args, **kwargs)
... return wrapper
>>> @helper
... def args(a, b):
... pass
>>> args(1, 2)
[('a', '1'), ('b', '2')]
>>> args(*(1,2))
[('a', '1'), ('b', '2')]
>>> args(1, b=2)
[('a', '1'), ('b', '2')]
>>> @helper
... def kwargs(a=1, b=2):
... pass
>>> kwargs()
[('a', '1'), ('b', '2')]
>>> kwargs(a=3, b=4)
[('a', '3'), ('b', '4')]
>>> kwargs(b=4, a=3)
[('a', '3'), ('b', '4')]
>>> kwargs(a=3)
[('a', '3'), ('b', '2')]
>>> kwargs(b=4)
[('a', '1'), ('b', '4')]
>>> @helper
... def args_kwargs(a, b, c=3, d=4):
... pass
>>> args_kwargs(1, 2)
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]
>>> args_kwargs(1, 2, d=5)
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '5')]
>>> args_kwargs(1, 2, 5, 6)
[('a', '1'), ('b', '2'), ('c', '5'), ('d', '6')]
>>> args_kwargs(1, b=2)
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]
>>> @helper
... def varargs(*a):
... pass
>>> varargs()
[]
>>> varargs(1, 2)
[('a', '(1, 2)')]
>>> @helper
... def keywords(**a):
... pass
>>> keywords()
[]
>>> keywords(a=1, b=2)
[('a', '1'), ('b', '2')]
>>> @helper
... def args_varargs(a, b, *c):
... pass
>>> args_varargs(1, 2)
[('a', '1'), ('b', '2')]
>>> args_varargs(1, 2, 2)
[('a', '1'), ('b', '2'), ('c', '(2,)')]
>>> @helper
... def args_kwargs_varargs(a, b, c=3, **d):
... pass
>>> args_kwargs_varargs(1, 2)
[('a', '1'), ('b', '2'), ('c', '3')]
>>> args_kwargs_varargs(1, 2, 4, d=5, e=6)
[('a', '1'), ('b', '2'), ('c', '4'), ('d', '5'), ('e', '6')]
>>> @helper
... def args_kwargs_varargs_keywords(a, b=2, *c, **d):
... pass
>>> args_kwargs_varargs_keywords(1)
[('a', '1'), ('b', '2')]
>>> args_kwargs_varargs_keywords(1, 2, 4, d=5, e=6)
[('a', '1'), ('b', '2'), ('c', '(4,)'), ('d', '5'), ('e', '6')]
>>> class Class:
... @staticmethod
... @helper
... def static_args(a, b):
... pass
...
... @classmethod
... @helper
... def method_args(cls, a, b):
... pass
...
... @helper
... def args(self, a, b):
... pass
>>> cls = Class()
>>> cls.args(1, 2)
[('a', '1'), ('b', '2')]
>>> cls.method_args(1, 2)
[('a', '1'), ('b', '2')]
>>> cls.static_args(1, 2)
[('a', '1'), ('b', '2')]
"""
parameters = {}
arg_spec = inspect.getfullargspec(func)
arg_order = list(arg_spec.args)
args_dict = dict(zip(arg_spec.args, args))
if arg_spec.defaults:
kwargs_defaults_dict = dict(zip(arg_spec.args[-len(arg_spec.defaults):], arg_spec.defaults))
parameters.update(kwargs_defaults_dict)
if arg_spec.varargs:
arg_order.append(arg_spec.varargs)
varargs = args[len(arg_spec.args):]
parameters.update({arg_spec.varargs: varargs} if varargs else {})
if arg_spec.args and arg_spec.args[0] in ['cls', 'self']:
args_dict.pop(arg_spec.args[0], None)
if kwargs:
if sys.version_info < (3, 7):
# Sort alphabetically as old python versions does
# not preserve call order for kwargs.
arg_order.extend(sorted(list(kwargs.keys())))
else:
# Keep py3.7 behaviour to preserve kwargs order
arg_order.extend(list(kwargs.keys()))
parameters.update(kwargs)
parameters.update(args_dict)
items = parameters.items()
sorted_items = sorted(
map(
lambda kv: (kv[0], represent(kv[1])),
items
),
key=lambda x: arg_order.index(x[0])
)
return collections.OrderedDict(sorted_items)
def format_traceback(exc_traceback):
return ''.join(traceback.format_tb(exc_traceback)) if exc_traceback else None
def format_exception(etype, value):
"""
>>> import sys
>>> try:
... assert False, ''
... except AssertionError:
... etype, e, _ = sys.exc_info()
... format_exception(etype, e) # doctest: +ELLIPSIS
'AssertionError: ...\\n'
>>> try:
... assert False, ''
... except AssertionError:
... etype, e, _ = sys.exc_info()
... format_exception(etype, e) # doctest: +ELLIPSIS
'AssertionError: ...\\n'
>>> try:
... compile("bla ''", "fake.py", "exec")
... except SyntaxError:
... etype, e, _ = sys.exc_info()
... format_exception(etype, e) # doctest: +ELLIPSIS
' File "fake.py", line 1...SyntaxError: invalid syntax\\n'
>>> try:
... compile("bla ''", "fake.py", "exec")
... except SyntaxError:
... etype, e, _ = sys.exc_info()
... format_exception(etype, e) # doctest: +ELLIPSIS
' File "fake.py", line 1...SyntaxError: invalid syntax\\n'
>>> from hamcrest import assert_that, equal_to
>>> try:
... assert_that('left', equal_to('right'))
... except AssertionError:
... etype, e, _ = sys.exc_info()
... format_exception(etype, e) # doctest: +ELLIPSIS
"AssertionError: \\nExpected:...but:..."
>>> try:
... assert_that('left', equal_to('right'))
... except AssertionError:
... etype, e, _ = sys.exc_info()
... format_exception(etype, e) # doctest: +ELLIPSIS
"AssertionError: \\nExpected:...but:..."
"""
return '\n'.join(format_exception_only(etype, value)) if etype or value else None
def get_testplan():
planned_tests = []
file_path = os.environ.get("ALLURE_TESTPLAN_PATH")
if file_path and os.path.exists(file_path):
with open(file_path, 'r') as plan_file:
plan = json.load(plan_file)
planned_tests = plan.get("tests", [])
return planned_tests
class SafeFormatter(string.Formatter):
"""
Format string safely - skip any non-passed keys
>>> f = SafeFormatter().format
Make sure we don't broke default formatting behaviour
>>> f("literal string")
'literal string'
>>> f("{expected.format}", expected=str)
""
>>> f("{expected[0]}", expected=["value"])
'value'
>>> f("{expected[0]}", expected=123)
Traceback (most recent call last):
...
TypeError: 'int' object is not subscriptable
>>> f("{expected[0]}", expected=[])
Traceback (most recent call last):
...
IndexError: list index out of range
>>> f("{expected.format}", expected=int)
Traceback (most recent call last):
...
AttributeError: type object 'int' has no attribute 'format'
Check that unexpected keys do not cause some errors
>>> f("{expected} {unexpected}", expected="value")
'value {unexpected}'
>>> f("{unexpected[0]}", expected=["value"])
'{unexpected[0]}'
>>> f("{unexpected.format}", expected=str)
'{unexpected.format}'
"""
class SafeKeyOrIndexError(Exception):
pass
def get_field(self, field_name, args, kwargs):
try:
return super().get_field(field_name, args, kwargs)
except self.SafeKeyOrIndexError:
return "{" + field_name + "}", field_name
def get_value(self, key, args, kwargs):
try:
return super().get_value(key, args, kwargs)
except (KeyError, IndexError):
raise self.SafeKeyOrIndexError()