Skip to content

Commit 82ae658

Browse files
committed
test: adapt to PyPy 3.9 v7.8.8
1 parent 87b2117 commit 82ae658

File tree

5 files changed

+134
-10
lines changed

5 files changed

+134
-10
lines changed

coverage/env.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ class PYBEHAVIOR:
5050
optimize_if_not_debug2 = (not PYPY) and (PYVERSION >= (3, 8, 0, 'beta', 1))
5151
if pep626:
5252
optimize_if_not_debug2 = False
53+
if PYPY and (PYVERSION >= (3, 9)):
54+
optimize_if_not_debug2 = True
5355

5456
# Yet another way to optimize "if not __debug__"?
55-
optimize_if_not_debug3 = (PYPY and PYVERSION >= (3, 8))
57+
optimize_if_not_debug3 = (PYPY and (3, 8) <= PYVERSION <= (3, 9))
5658

5759
# Can co_lnotab have negative deltas?
5860
negative_lnotab = not (PYPY and PYPYVERSION < (7, 2))
@@ -71,11 +73,19 @@ class PYBEHAVIOR:
7173
# (old behavior)?
7274
trace_decorated_def = (CPYTHON and PYVERSION >= (3, 8))
7375

76+
# Functions are no longer claimed to start at their earliest decorator even though
77+
# the decorators are traced?
78+
def_ast_no_decorator = (PYPY and PYVERSION >= (3, 9))
79+
80+
# CPython 3.11 now jumps to the decorator line again while executing
81+
# the decorator.
82+
trace_decorator_line_again = (CPYTHON and PYVERSION > (3, 11, 0, 'alpha', 3, 0))
83+
7484
# Are while-true loops optimized into absolute jumps with no loop setup?
7585
nix_while_true = (PYVERSION >= (3, 8))
7686

77-
# Python 3.9a1 made sys.argv[0] and other reported files absolute paths.
78-
report_absolute_files = (PYVERSION >= (3, 9))
87+
# CPython 3.9a1 made sys.argv[0] and other reported files absolute paths.
88+
report_absolute_files = (CPYTHON and PYVERSION >= (3, 9))
7989

8090
# Lines after break/continue/return/raise are no longer compiled into the
8191
# bytecode. They used to be marked as missing, now they aren't executable.
@@ -100,10 +110,6 @@ class PYBEHAVIOR:
100110
# Some words are keywords in some places, identifiers in other places.
101111
soft_keywords = (PYVERSION >= (3, 10))
102112

103-
# CPython 3.11 now jumps to the decorator line again while executing
104-
# the decorator.
105-
trace_decorator_line_again = (PYVERSION > (3, 11, 0, 'alpha', 3, 0))
106-
107113

108114
# Coverage.py specifics.
109115

coverage/parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ def line_for_node(self, node):
692692
def _line_decorated(self, node):
693693
"""Compute first line number for things that can be decorated (classes and functions)."""
694694
lineno = node.lineno
695-
if env.PYBEHAVIOR.trace_decorated_def:
695+
if env.PYBEHAVIOR.trace_decorated_def or env.PYBEHAVIOR.def_ast_no_decorator:
696696
if node.decorator_list:
697697
lineno = node.decorator_list[0].lineno
698698
return lineno
@@ -946,7 +946,7 @@ def _handle_decorated(self, node):
946946
main_line = last = node.lineno
947947
decs = node.decorator_list
948948
if decs:
949-
if env.PYBEHAVIOR.trace_decorated_def:
949+
if env.PYBEHAVIOR.trace_decorated_def or env.PYBEHAVIOR.def_ast_no_decorator:
950950
last = None
951951
for dec_node in decs:
952952
dec_start = self.line_for_node(dec_node)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
Comparing versions:
2+
3+
export PY38=/usr/local/pyenv/pyenv/versions/3.8.12/bin/python3.8
4+
export PY39=/usr/local/pyenv/pyenv/versions/3.9.10/bin/python3.9
5+
export PP38old=/usr/local/pypy/pypy3.8-v7.3.7-osx64/bin/pypy3
6+
export PP38=/usr/local/pypy/pypy3.8-v7.3.8rc1-osx64/bin/pypy3
7+
export PP39=/usr/local/pypy/pypy3.9-v7.3.8rc1-osx64/bin/pypy3
8+
9+
$ for py in $PY38 $PY39 $PP38old $PP38 $PP39; do $py -m coverage run --debug=pybehave igor.py; done 2>&1 | grep trace
10+
trace_decorated_def: True
11+
trace_decorator_line_again: False
12+
trace_decorated_def: True
13+
trace_decorator_line_again: False
14+
trace_decorated_def: False
15+
trace_decorator_line_again: False
16+
trace_decorated_def: False
17+
trace_decorator_line_again: False
18+
trace_decorated_def: False
19+
trace_decorator_line_again: False
20+
21+
# t466a_ast.py:
22+
import ast
23+
import sys
24+
25+
def find_function(node, name):
26+
if node.__class__.__name__ == "FunctionDef" and node.name == name:
27+
return node
28+
for node in getattr(node, "body", ()):
29+
fnode = find_function(node, name)
30+
if fnode is not None:
31+
return fnode
32+
33+
root_node = ast.parse(open(__file__).read())
34+
func_node = find_function(root_node, "parse")
35+
36+
print(func_node.name, func_node.lineno, func_node.end_lineno, tuple(sys.version_info), tuple(getattr(sys, "pypy_version_info", ())))
37+
38+
class Parser(object):
39+
40+
@classmethod
41+
def parse(cls):
42+
formats = [ 5 ]
43+
44+
45+
return None
46+
47+
Parser.parse()
48+
49+
50+
$ for py in $PY38 $PY39 $PP38old $PP38 $PP39; do $py t466a_ast.py; done
51+
parse 20 24 (3, 8, 12, 'final', 0) ()
52+
parse 20 24 (3, 9, 10, 'final', 0) ()
53+
parse 19 -1 (3, 8, 12, 'final', 0) (7, 3, 7, 'final', 0)
54+
parse 19 -1 (3, 8, 12, 'final', 0) (7, 3, 8, 'final', 0)
55+
parse 20 24 (3, 9, 10, 'final', 0) (7, 3, 8, 'final', 0)
56+
57+
58+
PyPy <=3.8 includes the decorator line in the FunctionDef node
59+
PyPy >=3.9 does not include the decorator line in the node
60+
61+
PyPy traces the decorator line, but not the def:
62+
63+
$ $PP38 -m trace --trace t466a_plain.py
64+
--- modulename: t466a_plain, funcname: <module>
65+
t466a_plain.py(1): class Parser(object):
66+
--- modulename: t466a_plain, funcname: Parser
67+
t466a_plain.py(1): class Parser(object):
68+
t466a_plain.py(3): @classmethod
69+
t466a_plain.py(10): Parser.parse()
70+
--- modulename: t466a_plain, funcname: parse
71+
t466a_plain.py(5): formats = [ 5 ]
72+
t466a_plain.py(8): return None
73+
74+
$ $PP39 -m trace --trace t466a_plain.py
75+
--- modulename: t466a_plain, funcname: <module>
76+
t466a_plain.py(1): class Parser(object):
77+
--- modulename: t466a_plain, funcname: Parser
78+
t466a_plain.py(1): class Parser(object):
79+
t466a_plain.py(3): @classmethod
80+
t466a_plain.py(10): Parser.parse()
81+
--- modulename: t466a_plain, funcname: parse
82+
t466a_plain.py(5): formats = [ 5 ]
83+
t466a_plain.py(8): return None
84+
85+
CPython traces the decorator and the def:
86+
87+
$ $PY39 -m trace --trace t466a_plain.py
88+
--- modulename: t466a_plain, funcname: <module>
89+
t466a_plain.py(1): class Parser(object):
90+
--- modulename: t466a_plain, funcname: Parser
91+
t466a_plain.py(1): class Parser(object):
92+
t466a_plain.py(3): @classmethod
93+
t466a_plain.py(4): def parse(cls):
94+
t466a_plain.py(10): Parser.parse()
95+
--- modulename: t466a_plain, funcname: parse
96+
t466a_plain.py(5): formats = [ 5 ]
97+
t466a_plain.py(8): return None

tests/test_arcs.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,11 @@ def test_finally_in_loop_bug_92(self):
926926
arcz=".1 12 23 35 56 61 17 7.",
927927
)
928928

929+
@pytest.mark.xfail(
930+
env.PYPY and env.PYVERSION >= (3, 9),
931+
reason="avoid a PyPy bug: 3662"
932+
# https://foss.heptapod.net/pypy/pypy/-/issues/3662
933+
)
929934
def test_bug_212(self):
930935
# "except Exception as e" is crucial here.
931936
# Bug 212 said that the "if exc" line was incorrectly marked as only
@@ -1653,6 +1658,11 @@ def f(a, b):
16531658
class DecoratorArcTest(CoverageTest):
16541659
"""Tests of arcs with decorators."""
16551660

1661+
@pytest.mark.xfail(
1662+
env.PYPY and env.PYVERSION >= (3, 9),
1663+
reason="avoid a PyPy bug: 3666"
1664+
# https://foss.heptapod.net/pypy/pypy/-/issues/3666
1665+
)
16561666
def test_function_decorator(self):
16571667
arcz = (
16581668
".1 16 67 7A AE EF F. " # main line
@@ -1681,6 +1691,11 @@ def my_function(
16811691
arcz=arcz,
16821692
)
16831693

1694+
@pytest.mark.xfail(
1695+
env.PYPY and env.PYVERSION >= (3, 9),
1696+
reason="avoid a PyPy bug: 3666"
1697+
# https://foss.heptapod.net/pypy/pypy/-/issues/3666
1698+
)
16841699
def test_class_decorator(self):
16851700
arcz = (
16861701
".1 16 67 6D 7A AE E. " # main line
@@ -1716,6 +1731,7 @@ def test_bug_466a(self):
17161731
arcz = arcz.replace("3.", "34 4.")
17171732
if env.PYBEHAVIOR.trace_decorator_line_again:
17181733
arcz += "43 "
1734+
# This example makes more sense when considered in tandem with 466b below.
17191735
self.check_coverage("""\
17201736
class Parser(object):
17211737
@@ -1832,7 +1848,7 @@ def test_lambda_in_dict(self):
18321848

18331849

18341850
xfail_eventlet_670 = pytest.mark.xfail(
1835-
env.PYVERSION[:2] == (3, 9) and env.OSX,
1851+
env.PYVERSION[:2] == (3, 9) and env.CPYTHON and env.OSX,
18361852
reason="Avoid an eventlet bug on Mac 3.9: eventlet#670",
18371853
# https://github.com/eventlet/eventlet/issues/670
18381854
)

tests/test_coverage.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,11 @@ def foo(
12181218
reason="avoid class docstring bug: bpo 46331",
12191219
# https://bugs.python.org/issue46331
12201220
)
1221+
@pytest.mark.xfail(
1222+
env.PYPY and env.PYVERSION[:2] == (3, 9),
1223+
reason="avoid PyPy class docstring bug: 3665",
1224+
# https://foss.heptapod.net/pypy/pypy/-/issues/3665
1225+
)
12211226
def test_class_def(self):
12221227
arcz="-22 2D DE E-2 23 36 6A A-2 -68 8-6 -AB B-A"
12231228
self.check_coverage("""\

0 commit comments

Comments
 (0)