diff options
-rw-r--r-- | coverage/env.py | 4 | ||||
-rw-r--r-- | coverage/parser.py | 10 | ||||
-rw-r--r-- | tests/test_arcs.py | 30 | ||||
-rw-r--r-- | tests/test_parser.py | 4 |
4 files changed, 38 insertions, 10 deletions
diff --git a/coverage/env.py b/coverage/env.py index 64d93e21..cf2f9d26 100644 --- a/coverage/env.py +++ b/coverage/env.py @@ -100,6 +100,10 @@ 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 665360fa..a96964d4 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -944,10 +944,11 @@ class AstArcAnalyzer: def _handle_decorated(self, node): """Add arcs for things that can be decorated (classes and functions).""" main_line = last = node.lineno - if node.decorator_list: + decs = node.decorator_list + if decs: if env.PYBEHAVIOR.trace_decorated_def: last = None - for dec_node in node.decorator_list: + for dec_node in decs: dec_start = self.line_for_node(dec_node) if last is not None and dec_start != last: self.add_arc(last, dec_start) @@ -955,6 +956,11 @@ class AstArcAnalyzer: if env.PYBEHAVIOR.trace_decorated_def: self.add_arc(last, main_line) last = main_line + if env.PYBEHAVIOR.trace_decorator_line_again: + for top, bot in zip(decs, decs[1:]): + self.add_arc(self.line_for_node(bot), self.line_for_node(top)) + self.add_arc(self.line_for_node(decs[0]), main_line) + self.add_arc(main_line, self.line_for_node(decs[-1])) # The definition line may have been missed, but we should have it # in `self.statements`. For some constructs, `line_for_node` is # not what we'd think of as the first line in the statement, so map diff --git a/tests/test_arcs.py b/tests/test_arcs.py index 978a3731..0635fcbc 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -1664,6 +1664,13 @@ class DecoratorArcTest(CoverageTest): """Tests of arcs with decorators.""" def test_function_decorator(self): + arcz = ( + ".1 16 67 7A AE EF F. " # main line + ".2 24 4. -23 3-2 " # decorators + "-6D D-6 " # my_function + ) + if env.PYBEHAVIOR.trace_decorator_line_again: + arcz += "A7 76 6A " self.check_coverage("""\ def decorator(arg): def _dec(f): @@ -1681,13 +1688,17 @@ class DecoratorArcTest(CoverageTest): a = 14 my_function() """, - arcz= - ".1 16 67 7A AE EF F. " # main line - ".2 24 4. -23 3-2 " # decorators - "-6D D-6 ", # my_function + arcz=arcz, ) def test_class_decorator(self): + arcz = ( + ".1 16 67 6D 7A AE E. " # main line + ".2 24 4. -23 3-2 " # decorators + "-66 D-6 " # MyObject + ) + if env.PYBEHAVIOR.trace_decorator_line_again: + arcz += "A7 76 6A " self.check_coverage("""\ def decorator(arg): def _dec(c): @@ -1704,10 +1715,7 @@ class DecoratorArcTest(CoverageTest): X = 13 a = 14 """, - arcz= - ".1 16 67 6D 7A AE E. " # main line - ".2 24 4. -23 3-2 " # decorators - "-66 D-6 ", # MyObject + arcz=arcz, ) def test_bug_466a(self): @@ -1716,6 +1724,8 @@ class DecoratorArcTest(CoverageTest): arcz = ".1 1A A. 13 3. -35 58 8-3 " if env.PYBEHAVIOR.trace_decorated_def: arcz = arcz.replace("3.", "34 4.") + if env.PYBEHAVIOR.trace_decorator_line_again: + arcz += "43 " self.check_coverage("""\ class Parser(object): @@ -1737,6 +1747,8 @@ class DecoratorArcTest(CoverageTest): arcz = ".1 1A A. 13 3. -35 58 8-3 " if env.PYBEHAVIOR.trace_decorated_def: arcz = arcz.replace("3.", "34 4.") + if env.PYBEHAVIOR.trace_decorator_line_again: + arcz += "43 " self.check_coverage("""\ class Parser(object): @@ -1925,6 +1937,8 @@ class AsyncTest(CoverageTest): arcz = ".1 14 4. .2 2. -46 6-4 " if env.PYBEHAVIOR.trace_decorated_def: arcz = arcz.replace("4.", "45 5.") + if env.PYBEHAVIOR.trace_decorator_line_again: + arcz += "54 " self.check_coverage("""\ def wrap(f): # 1 return f diff --git a/tests/test_parser.py b/tests/test_parser.py index 1e509035..2393ccd1 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -240,6 +240,10 @@ class PythonParserTest(CoverageTest): expected_arcs.update(set(arcz_to_arcs("-46 6-4"))) expected_exits.update({6: 1}) + if env.PYBEHAVIOR.trace_decorator_line_again: + expected_arcs.update(set(arcz_to_arcs("54 98"))) + expected_exits.update({9: 2, 5: 2}) + assert expected_statements == parser.statements assert expected_arcs == parser.arcs() assert expected_exits == parser.exit_counts() |