import string from uncompyle6 import PYTHON_VERSION import pytest pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7, reason="need at least Python 2.7") if PYTHON_VERSION > 2.6: from hypothesis import given, assume, example, settings, strategies as st from validate import validate_uncompyle from test_fstring import expressions alpha = st.sampled_from(string.ascii_lowercase) numbers = st.sampled_from(string.digits) alphanum = st.sampled_from(string.ascii_lowercase + string.digits) @st.composite def function_calls(draw, min_keyword_args=0, max_keyword_args=5, min_positional_args=0, max_positional_args=5, min_star_args=0, max_star_args=1, min_double_star_args=0, max_double_star_args=1): """ Strategy factory for generating function calls. :param draw: Callable which draws examples from other strategies. :return: The function call text. """ st_positional_args = st.lists( alpha, min_size=min_positional_args, max_size=max_positional_args ) st_keyword_args = st.lists( alpha, min_size=min_keyword_args, max_size=max_keyword_args ) st_star_args = st.lists( alpha, min_size=min_star_args, max_size=max_star_args ) st_double_star_args = st.lists( alpha, min_size=min_double_star_args, max_size=max_double_star_args ) positional_args = draw(st_positional_args) keyword_args = draw(st_keyword_args) st_values = st.lists( expressions(), min_size=len(keyword_args), max_size=len(keyword_args) ) keyword_args = [ x + '=' + e for x, e in zip(keyword_args, draw(st_values)) ] star_args = ['*' + x for x in draw(st_star_args)] double_star_args = ['**' + x for x in draw(st_double_star_args)] arguments = positional_args + keyword_args + star_args + double_star_args draw(st.randoms()).shuffle(arguments) arguments = ','.join(arguments) function_call = 'fn({arguments})'.format(arguments=arguments) try: # TODO: Figure out the exact rules for ordering of positional, keyword, # star args, double star args and in which versions the various # types of arguments are supported so we don't need to check that the # expression compiles like this. compile(function_call, '', 'single') except: assume(False) return function_call def test_function_no_args(): validate_uncompyle("fn()") @pytest.mark.skipif(PYTHON_VERSION < 2.7, reason="need at least Python 2.7") def isolated_function_calls(which): """ Returns a strategy for generating function calls, but isolated to particular types of arguments, for example only positional arguments. This can help reason about debugging errors in specific types of function calls. :param which: One of 'keyword', 'positional', 'star', 'double_star' :return: Strategy for generating an function call isolated to specific argument types. """ kwargs = dict( max_keyword_args=0, max_positional_args=0, max_star_args=0, max_double_star_args=0, ) kwargs['_'.join(('min', which, 'args'))] = 1 kwargs['_'.join(('max', which, 'args'))] = 5 if 'star' not in which else 1 return function_calls(**kwargs) with settings(max_examples=25): @pytest.mark.skipif(PYTHON_VERSION < 2.7, reason="need at least Python 2.7") @given(isolated_function_calls('positional')) @example("fn(0)") def test_function_positional_only(expr): validate_uncompyle(expr) @pytest.mark.skipif(PYTHON_VERSION < 2.7, reason="need at least Python 2.7") @given(isolated_function_calls('keyword')) @example("fn(a=0)") def test_function_call_keyword_only(expr): validate_uncompyle(expr) @pytest.mark.skipif(PYTHON_VERSION < 2.7, reason="need at least Python 2.7") @given(isolated_function_calls('star')) @example("fn(*items)") def test_function_call_star_only(expr): validate_uncompyle(expr) @pytest.mark.skipif(PYTHON_VERSION < 2.7, reason="need at least Python 2.7") @given(isolated_function_calls('double_star')) @example("fn(**{})") def test_function_call_double_star_only(expr): validate_uncompyle(expr) @pytest.mark.xfail() def test_BUILD_CONST_KEY_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX(): validate_uncompyle("fn(w=0,m=0,**v)") @pytest.mark.xfail() def test_BUILD_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX(): validate_uncompyle("fn(a=0,**g)") @pytest.mark.xfail() def test_CALL_FUNCTION_EX(): validate_uncompyle("fn(*g,**j)") @pytest.mark.xfail() def test_BUILD_MAP_CALL_FUNCTION_EX(): validate_uncompyle("fn(*z,u=0)") @pytest.mark.xfail() def test_BUILD_TUPLE_CALL_FUNCTION_EX(): validate_uncompyle("fn(**a)") @pytest.mark.xfail() def test_BUILD_MAP_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX(): validate_uncompyle("fn(b,b,b=0,*a)") @pytest.mark.xfail() def test_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX(): validate_uncompyle("fn(*c,v)") @pytest.mark.xfail() def test_BUILD_CONST_KEY_MAP_CALL_FUNCTION_EX(): validate_uncompyle("fn(i=0,y=0,*p)") @pytest.mark.skip(reason='skipping property based test until all individual tests are passing') @given(function_calls()) def test_function_call(function_call): validate_uncompyle(function_call)