summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2022-01-30 07:01:29 -0500
committerNed Batchelder <ned@nedbatchelder.com>2022-02-06 11:09:53 -0500
commit82ae658412ede7519d6212724e45714f8daa765e (patch)
treea8fac1b911aacd7515dc665741a1d0965223b6dd
parent87b2117f26677c21d7ffbf46b59b287183d4ca7a (diff)
downloadpython-coveragepy-git-82ae658412ede7519d6212724e45714f8daa765e.tar.gz
test: adapt to PyPy 3.9 v7.8.8
-rw-r--r--coverage/env.py20
-rw-r--r--coverage/parser.py4
-rw-r--r--lab/notes/pypy-738-decorated-functions.txt97
-rw-r--r--tests/test_arcs.py18
-rw-r--r--tests/test_coverage.py5
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("""\