diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2022-01-30 07:01:29 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2022-02-06 11:09:53 -0500 |
commit | 82ae658412ede7519d6212724e45714f8daa765e (patch) | |
tree | a8fac1b911aacd7515dc665741a1d0965223b6dd | |
parent | 87b2117f26677c21d7ffbf46b59b287183d4ca7a (diff) | |
download | python-coveragepy-git-82ae658412ede7519d6212724e45714f8daa765e.tar.gz |
test: adapt to PyPy 3.9 v7.8.8
-rw-r--r-- | coverage/env.py | 20 | ||||
-rw-r--r-- | coverage/parser.py | 4 | ||||
-rw-r--r-- | lab/notes/pypy-738-decorated-functions.txt | 97 | ||||
-rw-r--r-- | tests/test_arcs.py | 18 | ||||
-rw-r--r-- | tests/test_coverage.py | 5 |
5 files changed, 134 insertions, 10 deletions
diff --git a/coverage/env.py b/coverage/env.py index cf2f9d26..b76a206b 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -50,9 +50,11 @@ class PYBEHAVIOR: optimize_if_not_debug2 = (not PYPY) and (PYVERSION >= (3, 8, 0, 'beta', 1)) if pep626: optimize_if_not_debug2 = False + if PYPY and (PYVERSION >= (3, 9)): + optimize_if_not_debug2 = True # Yet another way to optimize "if not __debug__"? - optimize_if_not_debug3 = (PYPY and PYVERSION >= (3, 8)) + optimize_if_not_debug3 = (PYPY and (3, 8) <= PYVERSION <= (3, 9)) # Can co_lnotab have negative deltas? negative_lnotab = not (PYPY and PYPYVERSION < (7, 2)) @@ -71,11 +73,19 @@ class PYBEHAVIOR: # (old behavior)? trace_decorated_def = (CPYTHON and PYVERSION >= (3, 8)) + # Functions are no longer claimed to start at their earliest decorator even though + # the decorators are traced? + def_ast_no_decorator = (PYPY and PYVERSION >= (3, 9)) + + # CPython 3.11 now jumps to the decorator line again while executing + # the decorator. + trace_decorator_line_again = (CPYTHON and PYVERSION > (3, 11, 0, 'alpha', 3, 0)) + # Are while-true loops optimized into absolute jumps with no loop setup? nix_while_true = (PYVERSION >= (3, 8)) - # Python 3.9a1 made sys.argv[0] and other reported files absolute paths. - report_absolute_files = (PYVERSION >= (3, 9)) + # CPython 3.9a1 made sys.argv[0] and other reported files absolute paths. + report_absolute_files = (CPYTHON and PYVERSION >= (3, 9)) # Lines after break/continue/return/raise are no longer compiled into the # bytecode. They used to be marked as missing, now they aren't executable. @@ -100,10 +110,6 @@ class PYBEHAVIOR: # Some words are keywords in some places, identifiers in other places. soft_keywords = (PYVERSION >= (3, 10)) - # CPython 3.11 now jumps to the decorator line again while executing - # the decorator. - trace_decorator_line_again = (PYVERSION > (3, 11, 0, 'alpha', 3, 0)) - # Coverage.py specifics. diff --git a/coverage/parser.py b/coverage/parser.py index a96964d4..6a9f083c 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -692,7 +692,7 @@ class AstArcAnalyzer: def _line_decorated(self, node): """Compute first line number for things that can be decorated (classes and functions).""" lineno = node.lineno - if env.PYBEHAVIOR.trace_decorated_def: + if env.PYBEHAVIOR.trace_decorated_def or env.PYBEHAVIOR.def_ast_no_decorator: if node.decorator_list: lineno = node.decorator_list[0].lineno return lineno @@ -946,7 +946,7 @@ class AstArcAnalyzer: main_line = last = node.lineno decs = node.decorator_list if decs: - if env.PYBEHAVIOR.trace_decorated_def: + if env.PYBEHAVIOR.trace_decorated_def or env.PYBEHAVIOR.def_ast_no_decorator: last = None for dec_node in decs: dec_start = self.line_for_node(dec_node) diff --git a/lab/notes/pypy-738-decorated-functions.txt b/lab/notes/pypy-738-decorated-functions.txt new file mode 100644 index 00000000..21a685a6 --- /dev/null +++ b/lab/notes/pypy-738-decorated-functions.txt @@ -0,0 +1,97 @@ +Comparing versions: + +export PY38=/usr/local/pyenv/pyenv/versions/3.8.12/bin/python3.8 +export PY39=/usr/local/pyenv/pyenv/versions/3.9.10/bin/python3.9 +export PP38old=/usr/local/pypy/pypy3.8-v7.3.7-osx64/bin/pypy3 +export PP38=/usr/local/pypy/pypy3.8-v7.3.8rc1-osx64/bin/pypy3 +export PP39=/usr/local/pypy/pypy3.9-v7.3.8rc1-osx64/bin/pypy3 + +$ for py in $PY38 $PY39 $PP38old $PP38 $PP39; do $py -m coverage run --debug=pybehave igor.py; done 2>&1 | grep trace + trace_decorated_def: True + trace_decorator_line_again: False + trace_decorated_def: True + trace_decorator_line_again: False + trace_decorated_def: False + trace_decorator_line_again: False + trace_decorated_def: False + trace_decorator_line_again: False + trace_decorated_def: False + trace_decorator_line_again: False + +# t466a_ast.py: + import ast + import sys + + def find_function(node, name): + if node.__class__.__name__ == "FunctionDef" and node.name == name: + return node + for node in getattr(node, "body", ()): + fnode = find_function(node, name) + if fnode is not None: + return fnode + + root_node = ast.parse(open(__file__).read()) + func_node = find_function(root_node, "parse") + + print(func_node.name, func_node.lineno, func_node.end_lineno, tuple(sys.version_info), tuple(getattr(sys, "pypy_version_info", ()))) + + class Parser(object): + + @classmethod + def parse(cls): + formats = [ 5 ] + + + return None + + Parser.parse() + + +$ for py in $PY38 $PY39 $PP38old $PP38 $PP39; do $py t466a_ast.py; done +parse 20 24 (3, 8, 12, 'final', 0) () +parse 20 24 (3, 9, 10, 'final', 0) () +parse 19 -1 (3, 8, 12, 'final', 0) (7, 3, 7, 'final', 0) +parse 19 -1 (3, 8, 12, 'final', 0) (7, 3, 8, 'final', 0) +parse 20 24 (3, 9, 10, 'final', 0) (7, 3, 8, 'final', 0) + + +PyPy <=3.8 includes the decorator line in the FunctionDef node +PyPy >=3.9 does not include the decorator line in the node + +PyPy traces the decorator line, but not the def: + +$ $PP38 -m trace --trace t466a_plain.py + --- modulename: t466a_plain, funcname: <module> +t466a_plain.py(1): class Parser(object): + --- modulename: t466a_plain, funcname: Parser +t466a_plain.py(1): class Parser(object): +t466a_plain.py(3): @classmethod +t466a_plain.py(10): Parser.parse() + --- modulename: t466a_plain, funcname: parse +t466a_plain.py(5): formats = [ 5 ] +t466a_plain.py(8): return None + +$ $PP39 -m trace --trace t466a_plain.py + --- modulename: t466a_plain, funcname: <module> +t466a_plain.py(1): class Parser(object): + --- modulename: t466a_plain, funcname: Parser +t466a_plain.py(1): class Parser(object): +t466a_plain.py(3): @classmethod +t466a_plain.py(10): Parser.parse() + --- modulename: t466a_plain, funcname: parse +t466a_plain.py(5): formats = [ 5 ] +t466a_plain.py(8): return None + +CPython traces the decorator and the def: + +$ $PY39 -m trace --trace t466a_plain.py + --- modulename: t466a_plain, funcname: <module> +t466a_plain.py(1): class Parser(object): + --- modulename: t466a_plain, funcname: Parser +t466a_plain.py(1): class Parser(object): +t466a_plain.py(3): @classmethod +t466a_plain.py(4): def parse(cls): +t466a_plain.py(10): Parser.parse() + --- modulename: t466a_plain, funcname: parse +t466a_plain.py(5): formats = [ 5 ] +t466a_plain.py(8): return None diff --git a/tests/test_arcs.py b/tests/test_arcs.py index 6cb997dc..0141841a 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -926,6 +926,11 @@ class ExceptionArcTest(CoverageTest): arcz=".1 12 23 35 56 61 17 7.", ) + @pytest.mark.xfail( + env.PYPY and env.PYVERSION >= (3, 9), + reason="avoid a PyPy bug: 3662" + # https://foss.heptapod.net/pypy/pypy/-/issues/3662 + ) def test_bug_212(self): # "except Exception as e" is crucial here. # Bug 212 said that the "if exc" line was incorrectly marked as only @@ -1653,6 +1658,11 @@ class MiscArcTest(CoverageTest): class DecoratorArcTest(CoverageTest): """Tests of arcs with decorators.""" + @pytest.mark.xfail( + env.PYPY and env.PYVERSION >= (3, 9), + reason="avoid a PyPy bug: 3666" + # https://foss.heptapod.net/pypy/pypy/-/issues/3666 + ) def test_function_decorator(self): arcz = ( ".1 16 67 7A AE EF F. " # main line @@ -1681,6 +1691,11 @@ class DecoratorArcTest(CoverageTest): arcz=arcz, ) + @pytest.mark.xfail( + env.PYPY and env.PYVERSION >= (3, 9), + reason="avoid a PyPy bug: 3666" + # https://foss.heptapod.net/pypy/pypy/-/issues/3666 + ) def test_class_decorator(self): arcz = ( ".1 16 67 6D 7A AE E. " # main line @@ -1716,6 +1731,7 @@ class DecoratorArcTest(CoverageTest): arcz = arcz.replace("3.", "34 4.") if env.PYBEHAVIOR.trace_decorator_line_again: arcz += "43 " + # This example makes more sense when considered in tandem with 466b below. self.check_coverage("""\ class Parser(object): @@ -1832,7 +1848,7 @@ class LambdaArcTest(CoverageTest): xfail_eventlet_670 = pytest.mark.xfail( - env.PYVERSION[:2] == (3, 9) and env.OSX, + env.PYVERSION[:2] == (3, 9) and env.CPYTHON and env.OSX, reason="Avoid an eventlet bug on Mac 3.9: eventlet#670", # https://github.com/eventlet/eventlet/issues/670 ) diff --git a/tests/test_coverage.py b/tests/test_coverage.py index fc4263de..a6d3ccae 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -1218,6 +1218,11 @@ class CompoundStatementTest(CoverageTest): reason="avoid class docstring bug: bpo 46331", # https://bugs.python.org/issue46331 ) + @pytest.mark.xfail( + env.PYPY and env.PYVERSION[:2] == (3, 9), + reason="avoid PyPy class docstring bug: 3665", + # https://foss.heptapod.net/pypy/pypy/-/issues/3665 + ) def test_class_def(self): arcz="-22 2D DE E-2 23 36 6A A-2 -68 8-6 -AB B-A" self.check_coverage("""\ |