From ac2bbfc65a2f9ec676304d40161760522c5e72b8 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 12 Jun 2018 14:34:54 -0400 Subject: [PATCH] Disable hypothesis on 2.6.9 --- pytest/test_fstring.py | 246 ++++++++++++++-------------- pytest/test_function_call.py | 297 +++++++++++++++++----------------- pytest/test_single_compile.py | 35 ++-- 3 files changed, 292 insertions(+), 286 deletions(-) diff --git a/pytest/test_fstring.py b/pytest/test_fstring.py index 2789d82a..038d9417 100644 --- a/pytest/test_fstring.py +++ b/pytest/test_fstring.py @@ -1,150 +1,154 @@ # std -import os # test -import pytest -import hypothesis -from hypothesis import strategies as st -# uncompyle6 from uncompyle6 import PYTHON_VERSION, deparse_code +import pytest +pytestmark = pytest.mark.skipif(PYTHON_VERSION <= 2.6, + reason='hypothesis needs 2.7 or later') +if PYTHON_VERSION > 2.6: + + import hypothesis + from hypothesis import strategies as st + + # uncompyle6 -@st.composite -def expressions(draw): - # todo : would be nice to generate expressions using hypothesis however - # this is pretty involved so for now just use a corpus of expressions - # from which to select. - return draw(st.sampled_from(( - 'abc', - 'len(items)', - 'x + 1', - 'lineno', - 'container', - 'self.attribute', - 'self.method()', - # These expressions are failing, I think these are control - # flow problems rather than problems with FORMAT_VALUE, - # however I need to confirm this... - #'sorted(items, key=lambda x: x.name)', - #'func(*args, **kwargs)', - #'text or default', - #'43 if life_the_universe and everything else None' - ))) + @st.composite + def expressions(draw): + # todo : would be nice to generate expressions using hypothesis however + # this is pretty involved so for now just use a corpus of expressions + # from which to select. + return draw(st.sampled_from(( + 'abc', + 'len(items)', + 'x + 1', + 'lineno', + 'container', + 'self.attribute', + 'self.method()', + # These expressions are failing, I think these are control + # flow problems rather than problems with FORMAT_VALUE, + # however I need to confirm this... + #'sorted(items, key=lambda x: x.name)', + #'func(*args, **kwargs)', + #'text or default', + #'43 if life_the_universe and everything else None' + ))) -@st.composite -def format_specifiers(draw): - """ - Generate a valid format specifier using the rules: + @st.composite + def format_specifiers(draw): + """ + Generate a valid format specifier using the rules: - format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type] - fill ::= - align ::= "<" | ">" | "=" | "^" - sign ::= "+" | "-" | " " - width ::= integer - precision ::= integer - type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" + format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type] + fill ::= + align ::= "<" | ">" | "=" | "^" + sign ::= "+" | "-" | " " + width ::= integer + precision ::= integer + type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" - See https://docs.python.org/2/library/string.html + See https://docs.python.org/2/library/string.html - :param draw: Let hypothesis draw from other strategies. + :param draw: Let hypothesis draw from other strategies. - :return: An example format_specifier. - """ - alphabet_strategy = st.characters(min_codepoint=ord('a'), max_codepoint=ord('z')) - fill = draw(st.one_of(alphabet_strategy, st.none())) - align = draw(st.sampled_from(list('<>=^'))) - fill_align = (fill + align or '') if fill else '' + :return: An example format_specifier. + """ + alphabet_strategy = st.characters(min_codepoint=ord('a'), max_codepoint=ord('z')) + fill = draw(st.one_of(alphabet_strategy, st.none())) + align = draw(st.sampled_from(list('<>=^'))) + fill_align = (fill + align or '') if fill else '' - type_ = draw(st.sampled_from('bcdeEfFgGnosxX%')) - can_have_sign = type_ in 'deEfFgGnoxX%' - can_have_comma = type_ in 'deEfFgG%' - can_have_precision = type_ in 'fFgG' - can_have_pound = type_ in 'boxX%' - can_have_zero = type_ in 'oxX' + type_ = draw(st.sampled_from('bcdeEfFgGnosxX%')) + can_have_sign = type_ in 'deEfFgGnoxX%' + can_have_comma = type_ in 'deEfFgG%' + can_have_precision = type_ in 'fFgG' + can_have_pound = type_ in 'boxX%' + can_have_zero = type_ in 'oxX' - sign = draw(st.sampled_from(list('+- ') + [''])) if can_have_sign else '' - pound = draw(st.sampled_from(('#', '',))) if can_have_pound else '' - zero = draw(st.sampled_from(('0', '',))) if can_have_zero else '' + sign = draw(st.sampled_from(list('+- ') + [''])) if can_have_sign else '' + pound = draw(st.sampled_from(('#', '',))) if can_have_pound else '' + zero = draw(st.sampled_from(('0', '',))) if can_have_zero else '' - int_strategy = st.integers(min_value=1, max_value=1000) + int_strategy = st.integers(min_value=1, max_value=1000) - width = draw(st.one_of(int_strategy, st.none())) - width = str(width) if width is not None else '' + width = draw(st.one_of(int_strategy, st.none())) + width = str(width) if width is not None else '' - comma = draw(st.sampled_from((',', '',))) if can_have_comma else '' - if can_have_precision: - precision = draw(st.one_of(int_strategy, st.none())) - precision = '.' + str(precision) if precision else '' - else: - precision = '' + comma = draw(st.sampled_from((',', '',))) if can_have_comma else '' + if can_have_precision: + precision = draw(st.one_of(int_strategy, st.none())) + precision = '.' + str(precision) if precision else '' + else: + precision = '' - return ''.join((fill_align, sign, pound, zero, width, comma, precision, type_,)) + return ''.join((fill_align, sign, pound, zero, width, comma, precision, type_,)) -@st.composite -def fstrings(draw): - """ - Generate a valid f-string. - See https://www.python.org/dev/peps/pep-0498/#specification + @st.composite + def fstrings(draw): + """ + Generate a valid f-string. + See https://www.python.org/dev/peps/pep-0498/#specification - :param draw: Let hypothsis draw from other strategies. + :param draw: Let hypothsis draw from other strategies. - :return: A valid f-string. - """ - character_strategy = st.characters( - blacklist_characters='\r\n\'\\s{}', - min_codepoint=1, - max_codepoint=1000, - ) - is_raw = draw(st.booleans()) - integer_strategy = st.integers(min_value=0, max_value=3) - expression_count = draw(integer_strategy) - content = [] - for _ in range(expression_count): - expression = draw(expressions()) - conversion = draw(st.sampled_from(('', '!s', '!r', '!a',))) - has_specifier = draw(st.booleans()) - specifier = ':' + draw(format_specifiers()) if has_specifier else '' - content.append('{{{}{}}}'.format(expression, conversion, specifier)) - content.append(draw(st.text(character_strategy))) - content = ''.join(content) - return "f{}'{}'".format('r' if is_raw else '', content) + :return: A valid f-string. + """ + character_strategy = st.characters( + blacklist_characters='\r\n\'\\s{}', + min_codepoint=1, + max_codepoint=1000, + ) + is_raw = draw(st.booleans()) + integer_strategy = st.integers(min_value=0, max_value=3) + expression_count = draw(integer_strategy) + content = [] + for _ in range(expression_count): + expression = draw(expressions()) + conversion = draw(st.sampled_from(('', '!s', '!r', '!a',))) + has_specifier = draw(st.booleans()) + specifier = ':' + draw(format_specifiers()) if has_specifier else '' + content.append('{{{}{}}}'.format(expression, conversion, specifier)) + content.append(draw(st.text(character_strategy))) + content = ''.join(content) + return "f{}'{}'".format('r' if is_raw else '', content) -@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6') -@hypothesis.given(format_specifiers()) -def test_format_specifiers(format_specifier): - """Verify that format_specifiers generates valid specifiers""" - try: - exec('"{:' + format_specifier + '}".format(0)') - except ValueError as e: - if 'Unknown format code' not in str(e): - raise + @pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6') + @hypothesis.given(format_specifiers()) + def test_format_specifiers(format_specifier): + """Verify that format_specifiers generates valid specifiers""" + try: + exec('"{:' + format_specifier + '}".format(0)') + except ValueError as e: + if 'Unknown format code' not in str(e): + raise -def run_test(text): - hypothesis.assume(len(text)) - hypothesis.assume("f'{" in text) - expr = text + '\n' - code = compile(expr, '', 'single') - deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single') - recompiled = compile(deparsed.text, '', 'single') - if recompiled != code: - assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')' + def run_test(text): + hypothesis.assume(len(text)) + hypothesis.assume("f'{" in text) + expr = text + '\n' + code = compile(expr, '', 'single') + deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single') + recompiled = compile(deparsed.text, '', 'single') + if recompiled != code: + assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')' -@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6') -@hypothesis.given(fstrings()) -def test_uncompyle_fstring(fstring): - """Verify uncompyling fstring bytecode""" - run_test(fstring) + @pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6') + @hypothesis.given(fstrings()) + def test_uncompyle_fstring(fstring): + """Verify uncompyling fstring bytecode""" + run_test(fstring) -@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6') -@pytest.mark.parametrize('fstring', [ - "f'{abc}{abc!s}'", - "f'{abc}0'", -]) -def test_uncompyle_direct(fstring): - """useful for debugging""" - run_test(fstring) + @pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6') + @pytest.mark.parametrize('fstring', [ + "f'{abc}{abc!s}'", + "f'{abc}0'", + ]) + def test_uncompyle_direct(fstring): + """useful for debugging""" + run_test(fstring) diff --git a/pytest/test_function_call.py b/pytest/test_function_call.py index 4adb06a7..08bb1213 100644 --- a/pytest/test_function_call.py +++ b/pytest/test_function_call.py @@ -1,184 +1,185 @@ -# std import string -# 3rd party -from hypothesis import given, assume, example, settings, strategies as st -import pytest -# uncompyle -from validate import validate_uncompyle -from test_fstring import expressions from uncompyle6 import PYTHON_VERSION +import pytest +pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7, + reason="need at least Python 2.7") -alpha = st.sampled_from(string.ascii_lowercase) -numbers = st.sampled_from(string.digits) -alphanum = st.sampled_from(string.ascii_lowercase + string.digits) +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. + @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. + :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 - ) + :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)] + 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) + 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 + 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): + def test_function_no_args(): + validate_uncompyle("fn()") @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) + def isolated_function_calls(which): + """ + Returns a strategy for generating function calls, but isolated to + particular types of arguments, for example only positional arguments. - @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) + This can help reason about debugging errors in specific types of function + calls. - @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) + :param which: One of 'keyword', 'positional', 'star', 'double_star' - @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) + :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) -@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)") + 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_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX(): - validate_uncompyle("fn(a=0,**g)") + @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_CALL_FUNCTION_EX(): - validate_uncompyle("fn(*g,**j)") + @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_BUILD_MAP_CALL_FUNCTION_EX(): - validate_uncompyle("fn(*z,u=0)") + @pytest.mark.xfail() + def test_CALL_FUNCTION_EX(): + validate_uncompyle("fn(*g,**j)") -@pytest.mark.xfail() -def test_BUILD_TUPLE_CALL_FUNCTION_EX(): - validate_uncompyle("fn(**a)") + @pytest.mark.xfail() + def test_BUILD_MAP_CALL_FUNCTION_EX(): + validate_uncompyle("fn(*z,u=0)") -@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_CALL_FUNCTION_EX(): + validate_uncompyle("fn(**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_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_CONST_KEY_MAP_CALL_FUNCTION_EX(): - validate_uncompyle("fn(i=0,y=0,*p)") + @pytest.mark.xfail() + def test_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX(): + validate_uncompyle("fn(*c,v)") -@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) + @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) diff --git a/pytest/test_single_compile.py b/pytest/test_single_compile.py index 34f1ae31..78b5ea7d 100644 --- a/pytest/test_single_compile.py +++ b/pytest/test_single_compile.py @@ -1,21 +1,22 @@ import pytest from uncompyle6 import PYTHON_VERSION, deparse_code +pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7, + reason="need at least Python 2.7") -@pytest.mark.skip(PYTHON_VERSION < 2.7, - reason="need at least Python 2.7") -def test_single_mode(): - single_expressions = ( - 'i = 1', - 'i and (j or k)', - 'i += 1', - 'i = j % 4', - 'i = {}', - 'i = []', - 'for i in range(10):\n i\n', - 'for i in range(10):\n for j in range(10):\n i + j\n', - 'try:\n i\nexcept Exception:\n j\nelse:\n k\n' - ) +if PYTHON_VERSION > 2.6: + def test_single_mode(): + single_expressions = ( + 'i = 1', + 'i and (j or k)', + 'i += 1', + 'i = j % 4', + 'i = {}', + 'i = []', + 'for i in range(10):\n i\n', + 'for i in range(10):\n for j in range(10):\n i + j\n', + 'try:\n i\nexcept Exception:\n j\nelse:\n k\n' + ) - for expr in single_expressions: - code = compile(expr + '\n', '', 'single') - assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n' + for expr in single_expressions: + code = compile(expr + '\n', '', 'single') + assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n'