diff --git a/admin-tools/check-newer-versions.sh b/admin-tools/check-newer-versions.sh index bcb9608e..ed87f8bd 100755 --- a/admin-tools/check-newer-versions.sh +++ b/admin-tools/check-newer-versions.sh @@ -21,8 +21,9 @@ for version in $PYVERSIONS; do exit $? fi make clean && pip install -e . - if ! make check; then + if ! make check-short; then exit $? fi echo === $version === done +make check diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index dea7d670..b517a499 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.5.9 3.6.9 2.6.9 3.3.7 2.7.17 3.2.6 3.1.5 3.4.10 3.7.5' +export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.17 3.2.6 3.1.5 3.4.8 3.7.6 3.8.1' diff --git a/pytest/Makefile b/pytest/Makefile index 0eff67aa..cb4c0caa 100644 --- a/pytest/Makefile +++ b/pytest/Makefile @@ -1,7 +1,11 @@ PHONY=check test pytest +SHELL=/bin/bash PYTHON ?= python #: Run all tests test check pytest: - py.test + @PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \ + if [[ $$PYTHON_VERSION > 3.2 ]] || [[ $$PYTHON_VERSION == 2.7 ]] || [[ $$PYTHON_VERSION == 2.6 ]]; then \ + py.test; \ + fi diff --git a/pytest/test_fstring.py b/pytest/test_fstring.py deleted file mode 100644 index 5e486476..00000000 --- a/pytest/test_fstring.py +++ /dev/null @@ -1,158 +0,0 @@ -# std -# test -import sys -from uncompyle6 import PYTHON_VERSION, code_deparse -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 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" | "%" - - See https://docs.python.org/2/library/string.html - - :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 "" - - 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 "" - - 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 "" - - 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_)) - - @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. - - :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 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 = code_deparse(code, sys.stdout, PYTHON_VERSION, compile_mode="single") - recompiled = compile(deparsed.text, "", "single") - if recompiled != code: - print(recompiled) - print("================") - print(code) - print("----------------") - assert ( - "dis(" + deparsed.text.strip("\n") + ")" - == "dis(" + expr.strip("\n") + ")" - ) - - @pytest.mark.skipif(PYTHON_VERSION != 3.6, reason="need 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 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 deleted file mode 100644 index 08bb1213..00000000 --- a/pytest/test_function_call.py +++ /dev/null @@ -1,185 +0,0 @@ -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) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 0978553c..bf66b226 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -67,20 +67,14 @@ def test_grammar(): (("l_stmts", ("lastl_stmt", "come_froms", "l_stmts"))) ) pass - elif 3.0 < PYTHON_VERSION < 3.3: - expect_right_recursive.add( - (("l_stmts", ("lastl_stmt", "COME_FROM", "l_stmts"))) - ) - pass pass pass else: expect_lhs.add("kwarg") - assert expect_lhs == set(lhs) - # FIXME - if PYTHON_VERSION != 3.8: + if PYTHON_VERSION < 3.8: + assert expect_lhs == set(lhs) assert unused_rhs == set(rhs) assert expect_right_recursive == right_recursive diff --git a/requirements-dev.txt b/requirements-dev.txt index 77c74ff3..df568d76 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,3 @@ flake8 -hypothesis<=3.0.0 six -pytest==3.2.5 +pytest==3.2.5 # for 2.7 < PYTHON_VERSION <= 3.2 use pytest 2.9.2; for 3.1 2.10