diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2021-08-14 19:24:10 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2021-08-14 19:28:18 -0400 |
commit | f6d3e88ba5b2dab1720281885c99cdf3ce2844bc (patch) | |
tree | 17acde78dbc8695d7ba19f3a164ebabb30dfde73 | |
parent | a996e357d1e82c8ed08cda0a43a5ab0fa05f68fd (diff) | |
download | python-coveragepy-git-f6d3e88ba5b2dab1720281885c99cdf3ce2844bc.tar.gz |
fix: missing exceptions through with statements in 3.10 aren't considered missing branches. #1205
-rw-r--r-- | CHANGES.rst | 5 | ||||
-rw-r--r-- | coverage/parser.py | 12 | ||||
-rw-r--r-- | tests/test_arcs.py | 56 |
3 files changed, 65 insertions, 8 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 0fc84cb3..4baa8a36 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -37,6 +37,10 @@ Unreleased now warnings, to ease the use of coverage across versions. Fixes `issue 1035`_. +- Fix handling of exceptions through context managers in Python 3.10. A missing + exception is no longer considered a missing branch from the with statement. + Fixes `issue 1205`_. + - Fix another rarer instance of "Error binding parameter 0 - probably unsupported type." (`issue 1010`_). @@ -44,6 +48,7 @@ Unreleased .. _issue 1105: https://github.com/nedbat/coveragepy/issues/1105 .. _issue 1163: https://github.com/nedbat/coveragepy/issues/1163 .. _issue 1195: https://github.com/nedbat/coveragepy/issues/1195 +.. _issue 1205: https://github.com/nedbat/coveragepy/issues/1205 .. _changes_60b1: diff --git a/coverage/parser.py b/coverage/parser.py index 8d4e9ffb..8792d0ac 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -556,14 +556,14 @@ class WithBlock(BlockBase): # that need to go through the with-statement while exiting. self.break_from = set() self.continue_from = set() - self.raise_from = set() self.return_from = set() - def _process_exits(self, exits, add_arc, from_set): + def _process_exits(self, exits, add_arc, from_set=None): """Helper to process the four kinds of exits.""" for xit in exits: add_arc(xit.lineno, self.start, xit.cause) - from_set.update(exits) + if from_set is not None: + from_set.update(exits) return True def process_break_exits(self, exits, add_arc): @@ -573,7 +573,7 @@ class WithBlock(BlockBase): return self._process_exits(exits, add_arc, self.continue_from) def process_raise_exits(self, exits, add_arc): - return self._process_exits(exits, add_arc, self.raise_from) + return self._process_exits(exits, add_arc) def process_return_exits(self, exits, add_arc): return self._process_exits(exits, add_arc, self.return_from) @@ -1232,10 +1232,6 @@ class AstArcAnalyzer: self.process_continue_exits( self._combine_finally_starts(with_block.continue_from, with_exit) ) - if with_block.raise_from: - self.process_raise_exits( - self._combine_finally_starts(with_block.raise_from, with_exit) - ) if with_block.return_from: self.process_return_exits( self._combine_finally_starts(with_block.return_from, with_exit) diff --git a/tests/test_arcs.py b/tests/test_arcs.py index 5059fdc7..f1b57c57 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -279,6 +279,62 @@ class WithTest(CoverageTest): arcz=arcz, ) + def test_raise_through_with(self): + if env.PYBEHAVIOR.exit_through_with: + arcz = ".1 12 27 78 8. 9A A. -23 34 45 53 6-2" + arcz_missing = "6-2 8." + arcz_unpredicted = "3-2 89" + else: + arcz = ".1 12 27 78 8. 9A A. -23 34 45 5-2 6-2" + arcz_missing = "6-2 8." + arcz_unpredicted = "89" + cov = self.check_coverage("""\ + from contextlib import suppress + def f(x): + with suppress(): # used as a null context manager + print(4) + raise Exception("Boo6") + print(6) + try: + f(8) + except Exception: + print("oops 10") + """, + arcz=arcz, + arcz_missing=arcz_missing, + arcz_unpredicted=arcz_unpredicted, + ) + expected = "line 3 didn't jump to the function exit" + assert self.get_missing_arc_description(cov, 3, -2) == expected + + def test_untaken_raise_through_with(self): + if env.PYBEHAVIOR.exit_through_with: + #arcz = ".1 12 28 89 9. AB B. -23 3-2 34 45 56 53 63 37 7-2" + arcz = ".1 12 28 89 9. AB B. -23 34 45 56 53 63 37 7-2" + #arcz_missing = "3-2 56 63 AB B." + arcz_missing = "56 63 AB B." + else: + arcz = ".1 12 28 89 9. AB B. -23 34 45 56 6-2 57 7-2" + arcz_missing = "56 6-2 AB B." + cov = self.check_coverage("""\ + from contextlib import suppress + def f(x): + with suppress(): # used as a null context manager + print(4) + if x == 5: + raise Exception("Boo6") + print(7) + try: + f(9) + except Exception: + print("oops 11") + """, + arcz=arcz, + arcz_missing=arcz_missing, + ) + expected = "line 3 didn't jump to the function exit" + assert self.get_missing_arc_description(cov, 3, -2) == expected + class LoopArcTest(CoverageTest): """Arc-measuring tests involving loops.""" |